pl-fe: migrate status interactions to tanstack query
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -15,7 +15,6 @@ const REBLOG_REQUEST = 'REBLOG_REQUEST' as const;
|
||||
const REBLOG_FAIL = 'REBLOG_FAIL' as const;
|
||||
|
||||
const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST' as const;
|
||||
const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS' as const;
|
||||
const FAVOURITE_FAIL = 'FAVOURITE_FAIL' as const;
|
||||
|
||||
const DISLIKE_REQUEST = 'DISLIKE_REQUEST' as const;
|
||||
@ -25,7 +24,6 @@ const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST' as const;
|
||||
const UNREBLOG_FAIL = 'UNREBLOG_FAIL' as const;
|
||||
|
||||
const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST' as const;
|
||||
const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS' as const;
|
||||
|
||||
const UNDISLIKE_REQUEST = 'UNDISLIKE_REQUEST' as const;
|
||||
|
||||
@ -37,8 +35,6 @@ const BOOKMARK_SUCCESS = 'BOOKMARKED_SUCCESS' as const;
|
||||
|
||||
const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS' as const;
|
||||
|
||||
const noOp = () => new Promise(f => f(undefined));
|
||||
|
||||
const messages = defineMessages({
|
||||
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
||||
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
||||
@ -47,166 +43,59 @@ const messages = defineMessages({
|
||||
selectFolder: { id: 'status.bookmark.select_folder', defaultMessage: 'Select folder' },
|
||||
});
|
||||
|
||||
const reblog = (status: Pick<Status, 'id'>, visibility?: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return noOp();
|
||||
interface ReblogRequest {
|
||||
type: typeof REBLOG_REQUEST;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
dispatch(reblogRequest(status.id));
|
||||
interface ReblogFail {
|
||||
type: typeof REBLOG_FAIL;
|
||||
statusId: string;
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
return getClient(getState()).statuses.reblogStatus(status.id, visibility).then((response) => {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
if (response.reblog) dispatch(importEntities({ statuses: [response.reblog] }));
|
||||
}).catch(error => {
|
||||
dispatch(reblogFail(status.id, error));
|
||||
});
|
||||
};
|
||||
interface UnreblogRequest {
|
||||
type: typeof UNREBLOG_REQUEST;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
const unreblog = (status: Pick<Status, 'id'>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return noOp();
|
||||
interface UnreblogFail {
|
||||
type: typeof UNREBLOG_FAIL;
|
||||
statusId: string;
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
dispatch(unreblogRequest(status.id));
|
||||
interface FavouriteRequest {
|
||||
type: typeof FAVOURITE_REQUEST;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
return getClient(getState()).statuses.unreblogStatus(status.id).catch(error => {
|
||||
dispatch(unreblogFail(status.id, error));
|
||||
});
|
||||
};
|
||||
interface FavouriteFail {
|
||||
type: typeof FAVOURITE_FAIL;
|
||||
statusId: string;
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
const toggleReblog = (status: Pick<Status, 'id' | 'reblogged'>, visibility?: string) => {
|
||||
if (status.reblogged) {
|
||||
return unreblog(status);
|
||||
} else {
|
||||
return reblog(status, visibility);
|
||||
}
|
||||
};
|
||||
interface UnfavouriteRequest {
|
||||
type: typeof UNFAVOURITE_REQUEST;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
const reblogRequest = (statusId: string) => ({
|
||||
type: REBLOG_REQUEST,
|
||||
statusId,
|
||||
});
|
||||
interface DislikeRequest {
|
||||
type: typeof DISLIKE_REQUEST;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
const reblogFail = (statusId: string, error: unknown) => ({
|
||||
type: REBLOG_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
});
|
||||
interface DislikeFail {
|
||||
type: typeof DISLIKE_FAIL;
|
||||
statusId: string;
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
const unreblogRequest = (statusId: string) => ({
|
||||
type: UNREBLOG_REQUEST,
|
||||
statusId,
|
||||
});
|
||||
|
||||
const unreblogFail = (statusId: string, error: unknown) => ({
|
||||
type: UNREBLOG_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
});
|
||||
|
||||
const favourite = (status: Pick<Status, 'id'>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return noOp();
|
||||
|
||||
dispatch(favouriteRequest(status.id));
|
||||
|
||||
return getClient(getState()).statuses.favouriteStatus(status.id).then((response) => {
|
||||
dispatch(favouriteSuccess(response));
|
||||
}).catch((error) => {
|
||||
dispatch(favouriteFail(status.id, error));
|
||||
});
|
||||
};
|
||||
|
||||
const unfavourite = (status: Pick<Status, 'id'>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return noOp();
|
||||
|
||||
dispatch(unfavouriteRequest(status.id));
|
||||
|
||||
return getClient(getState()).statuses.unfavouriteStatus(status.id).then((response) => {
|
||||
dispatch(unfavouriteSuccess(response));
|
||||
});
|
||||
};
|
||||
|
||||
const toggleFavourite = (status: Pick<Status, 'id' | 'favourited'>) => {
|
||||
if (status.favourited) {
|
||||
return unfavourite(status);
|
||||
} else {
|
||||
return favourite(status);
|
||||
}
|
||||
};
|
||||
|
||||
const favouriteRequest = (statusId: string) => ({
|
||||
type: FAVOURITE_REQUEST,
|
||||
statusId,
|
||||
});
|
||||
|
||||
const favouriteSuccess = (status: Status) => ({
|
||||
type: FAVOURITE_SUCCESS,
|
||||
status,
|
||||
statusId: status.id,
|
||||
});
|
||||
|
||||
const favouriteFail = (statusId: string, error: unknown) => ({
|
||||
type: FAVOURITE_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
});
|
||||
|
||||
const unfavouriteRequest = (statusId: string) => ({
|
||||
type: UNFAVOURITE_REQUEST,
|
||||
statusId,
|
||||
});
|
||||
|
||||
const unfavouriteSuccess = (status: Status) => ({
|
||||
type: UNFAVOURITE_SUCCESS,
|
||||
status,
|
||||
statusId: status.id,
|
||||
});
|
||||
|
||||
const dislike = (status: Pick<Status, 'id'>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(dislikeRequest(status.id));
|
||||
|
||||
return getClient(getState).statuses.dislikeStatus(status.id).catch((error) => {
|
||||
dispatch(dislikeFail(status.id, error));
|
||||
});
|
||||
};
|
||||
|
||||
const undislike = (status: Pick<Status, 'id'>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(undislikeRequest(status.id));
|
||||
|
||||
return getClient(getState).statuses.undislikeStatus(status.id);
|
||||
};
|
||||
|
||||
const toggleDislike = (status: Pick<Status, 'id' | 'disliked'>) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
if (status.disliked) {
|
||||
dispatch(undislike(status));
|
||||
} else {
|
||||
dispatch(dislike(status));
|
||||
}
|
||||
};
|
||||
|
||||
const dislikeRequest = (statusId: string) => ({
|
||||
type: DISLIKE_REQUEST,
|
||||
statusId,
|
||||
});
|
||||
|
||||
const dislikeFail = (statusId: string, error: unknown) => ({
|
||||
type: DISLIKE_FAIL,
|
||||
statusId,
|
||||
error,
|
||||
});
|
||||
|
||||
const undislikeRequest = (statusId: string) => ({
|
||||
type: UNDISLIKE_REQUEST,
|
||||
statusId,
|
||||
});
|
||||
interface UndislikeRequest {
|
||||
type: typeof UNDISLIKE_REQUEST;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
const bookmark = (status: Pick<Status, 'id'>, folderId?: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
@ -318,18 +207,16 @@ const remoteInteraction = (ap_id: string, profile: string) =>
|
||||
getClient(getState).accounts.remoteInteraction(ap_id, profile).then((data) => data.url);
|
||||
|
||||
type InteractionsAction =
|
||||
| ReturnType<typeof reblogRequest>
|
||||
| ReturnType<typeof reblogFail>
|
||||
| ReturnType<typeof unreblogRequest>
|
||||
| ReturnType<typeof unreblogFail>
|
||||
| ReturnType<typeof favouriteRequest>
|
||||
| ReturnType<typeof favouriteSuccess>
|
||||
| ReturnType<typeof favouriteFail>
|
||||
| ReturnType<typeof unfavouriteRequest>
|
||||
| ReturnType<typeof unfavouriteSuccess>
|
||||
| ReturnType<typeof dislikeRequest>
|
||||
| ReturnType<typeof dislikeFail>
|
||||
| ReturnType<typeof undislikeRequest>
|
||||
| ReblogRequest
|
||||
| ReblogFail
|
||||
| UnreblogRequest
|
||||
| UnreblogFail
|
||||
| FavouriteRequest
|
||||
| FavouriteFail
|
||||
| UnfavouriteRequest
|
||||
| DislikeRequest
|
||||
| DislikeFail
|
||||
| UndislikeRequest
|
||||
| ReturnType<typeof bookmarkSuccess>
|
||||
| ReturnType<typeof unbookmarkSuccess>
|
||||
| ReturnType<typeof pinSuccess>
|
||||
@ -339,26 +226,17 @@ export {
|
||||
REBLOG_REQUEST,
|
||||
REBLOG_FAIL,
|
||||
FAVOURITE_REQUEST,
|
||||
FAVOURITE_SUCCESS,
|
||||
FAVOURITE_FAIL,
|
||||
DISLIKE_REQUEST,
|
||||
DISLIKE_FAIL,
|
||||
UNREBLOG_REQUEST,
|
||||
UNREBLOG_FAIL,
|
||||
UNFAVOURITE_REQUEST,
|
||||
UNFAVOURITE_SUCCESS,
|
||||
UNDISLIKE_REQUEST,
|
||||
PIN_SUCCESS,
|
||||
UNPIN_SUCCESS,
|
||||
BOOKMARK_SUCCESS,
|
||||
UNBOOKMARK_SUCCESS,
|
||||
reblog,
|
||||
unreblog,
|
||||
toggleReblog,
|
||||
favourite,
|
||||
unfavourite,
|
||||
toggleFavourite,
|
||||
toggleDislike,
|
||||
bookmark,
|
||||
toggleBookmark,
|
||||
togglePin,
|
||||
|
||||
@ -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, toggleDislike, toggleFavourite, togglePin, toggleReblog } from 'pl-fe/actions/interactions';
|
||||
import { toggleBookmark, 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,6 +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 { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useStatusMetaStore } from 'pl-fe/stores/status-meta';
|
||||
import toast from 'pl-fe/toast';
|
||||
@ -288,6 +289,9 @@ const ReblogButton: React.FC<IReblogButton> = ({
|
||||
const { openModal } = useModalsStore();
|
||||
const canReblog = useCanInteract(status, 'can_reblog');
|
||||
|
||||
const { mutate: reblogStatus } = useReblogStatus(status.id);
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(status.id);
|
||||
|
||||
let reblogIcon = require('@tabler/icons/outline/repeat.svg');
|
||||
|
||||
if (status.visibility === 'direct') {
|
||||
@ -298,9 +302,17 @@ const ReblogButton: React.FC<IReblogButton> = ({
|
||||
|
||||
const handleReblogClick: React.EventHandler<React.MouseEvent> = e => {
|
||||
if (me) {
|
||||
const modalReblog = () => dispatch(toggleReblog(status)).then(() => {
|
||||
if (canReblog.approvalRequired) toast.info(messages.reblogApprovalRequired);
|
||||
});
|
||||
const modalReblog = () => {
|
||||
if (status.reblogged) {
|
||||
unreblogStatus();
|
||||
} else {
|
||||
reblogStatus(undefined, {
|
||||
onSuccess: () => {
|
||||
if (canReblog.approvalRequired) toast.info(messages.reblogApprovalRequired);
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
@ -377,18 +389,26 @@ const FavouriteButton: React.FC<IActionButton> = ({
|
||||
withLabels,
|
||||
onOpenUnauthorizedModal,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
|
||||
const { openModal } = useModalsStore();
|
||||
const canFavourite = useCanInteract(status, 'can_favourite');
|
||||
|
||||
const { mutate: favouriteStatus } = useFavouriteStatus(status.id);
|
||||
const { mutate: unfavouriteStatus } = useUnfavouriteStatus(status.id);
|
||||
|
||||
const handleFavouriteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(toggleFavourite(status)).then(() => {
|
||||
if (canFavourite.approvalRequired) toast.info(messages.favouriteApprovalRequired);
|
||||
}).catch(() => {});
|
||||
if (status.favourited) {
|
||||
unfavouriteStatus();
|
||||
} else {
|
||||
favouriteStatus(undefined, {
|
||||
onSuccess: () => {
|
||||
if (canFavourite.approvalRequired) toast.info(messages.favouriteApprovalRequired);
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
onOpenUnauthorizedModal('FAVOURITE');
|
||||
}
|
||||
@ -431,17 +451,23 @@ const DislikeButton: React.FC<IActionButton> = ({
|
||||
me,
|
||||
onOpenUnauthorizedModal,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
const { mutate: dislikeStatus } = useDislikeStatus(status.id);
|
||||
const { mutate: undislikeStatus } = useUndislikeStatus(status.id);
|
||||
|
||||
if (!features.statusDislikes) return;
|
||||
|
||||
const handleDislikeClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(toggleDislike(status));
|
||||
if (status.disliked) {
|
||||
undislikeStatus();
|
||||
} else {
|
||||
dislikeStatus();
|
||||
}
|
||||
} else {
|
||||
onOpenUnauthorizedModal('DISLIKE');
|
||||
}
|
||||
@ -603,6 +629,8 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
const { autoTranslate, deleteModal, knownLanguages } = useSettings();
|
||||
|
||||
const { translationLanguages } = useTranslationLanguages();
|
||||
const { mutate: reblogStatus } = useReblogStatus(status.id);
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(status.id);
|
||||
|
||||
const autoTranslating = useMemo(() => {
|
||||
const {
|
||||
@ -666,7 +694,10 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
};
|
||||
|
||||
const handleReblogClick = (e: React.MouseEvent | React.KeyboardEvent, visibility?: string) => {
|
||||
const modalReblog = () => dispatch(toggleReblog(status, visibility));
|
||||
const modalReblog = () => {
|
||||
if (status.reblogged) unreblogStatus();
|
||||
else reblogStatus(visibility);
|
||||
};
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
|
||||
@ -4,7 +4,6 @@ import { defineMessages, useIntl, FormattedList, FormattedMessage } from 'react-
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
|
||||
import { mentionCompose, replyCompose } from 'pl-fe/actions/compose';
|
||||
import { toggleFavourite, toggleReblog } from 'pl-fe/actions/interactions';
|
||||
import { unfilterStatus } from 'pl-fe/actions/statuses';
|
||||
import Card from 'pl-fe/components/ui/card';
|
||||
import Icon from 'pl-fe/components/ui/icon';
|
||||
@ -17,6 +16,7 @@ import { HotKeys } from 'pl-fe/features/ui/components/hotkeys';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useSettings } from 'pl-fe/hooks/use-settings';
|
||||
import { useFavouriteStatus, useReblogStatus, useUnfavouriteStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { makeGetStatus, type SelectedStatus } from 'pl-fe/selectors';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useStatusMetaStore } from 'pl-fe/stores/status-meta';
|
||||
@ -88,6 +88,11 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
const getStatus = useMemo(makeGetStatus, []);
|
||||
const actualStatus = useAppSelector(state => status.reblog_id && getStatus(state, { id: status.reblog_id }) || status)!;
|
||||
|
||||
const { mutate: favouriteStatus } = useFavouriteStatus(actualStatus.id);
|
||||
const { mutate: unfavouriteStatus } = useUnfavouriteStatus(actualStatus.id);
|
||||
const { mutate: reblogStatus } = useReblogStatus(actualStatus.id);
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(actualStatus.id);
|
||||
|
||||
const isReblog = status.reblog_id;
|
||||
const statusUrl = `/@${actualStatus.account.acct}/posts/${actualStatus.id}`;
|
||||
const group = actualStatus.group;
|
||||
@ -140,11 +145,15 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
|
||||
const handleHotkeyFavourite = (e?: KeyboardEvent) => {
|
||||
e?.preventDefault();
|
||||
dispatch(toggleFavourite(actualStatus));
|
||||
if (status.favourited) unfavouriteStatus();
|
||||
else favouriteStatus();
|
||||
};
|
||||
|
||||
const handleHotkeyBoost = (e?: KeyboardEvent) => {
|
||||
const modalReblog = () => dispatch(toggleReblog(actualStatus));
|
||||
const modalReblog = () => {
|
||||
if (status.reblogged) unreblogStatus();
|
||||
else reblogStatus(undefined);
|
||||
};
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
|
||||
@ -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, toggleReblog } from 'pl-fe/actions/interactions';
|
||||
import { toggleBookmark, 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,6 +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 { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import copy from 'pl-fe/utils/copy';
|
||||
import { download } from 'pl-fe/utils/download';
|
||||
@ -89,6 +90,9 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
||||
const isStaff = ownAccount ? ownAccount.is_admin || ownAccount.is_moderator : false;
|
||||
const isAdmin = ownAccount ? ownAccount.is_admin : false;
|
||||
|
||||
const { mutate: reblogStatus } = useReblogStatus(status?.id!);
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(status?.id!);
|
||||
|
||||
if (!status || !status.event) {
|
||||
return (
|
||||
<>
|
||||
@ -131,7 +135,10 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
||||
};
|
||||
|
||||
const handleReblogClick = (visibility?: string) => {
|
||||
const modalReblog = () => dispatch(toggleReblog(status, visibility));
|
||||
const modalReblog = () => {
|
||||
if (status.reblogged) unreblogStatus();
|
||||
else reblogStatus(visibility);
|
||||
};
|
||||
if (!boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
|
||||
@ -3,7 +3,6 @@ import { defineMessages, useIntl, FormattedList, FormattedMessage, IntlShape, Me
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
|
||||
import { mentionCompose, replyCompose } from 'pl-fe/actions/compose';
|
||||
import { reblog, favourite, unreblog, unfavourite } from 'pl-fe/actions/interactions';
|
||||
import HoverAccountWrapper from 'pl-fe/components/hover-account-wrapper';
|
||||
import Icon from 'pl-fe/components/icon';
|
||||
import RelativeTimestamp from 'pl-fe/components/relative-timestamp';
|
||||
@ -18,6 +17,7 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useLoggedIn } from 'pl-fe/hooks/use-logged-in';
|
||||
import { useFavouriteStatus, useUnfavouriteStatus, useReblogStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { makeGetNotification } from 'pl-fe/selectors';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useSettingsStore } from 'pl-fe/stores/settings';
|
||||
@ -211,6 +211,11 @@ const Notification: React.FC<INotification> = (props) => {
|
||||
const notification = useAppSelector((state) => getNotification(state, props.notification));
|
||||
const status = getNotificationStatus(notification);
|
||||
|
||||
const { mutate: favouriteStatus } = useFavouriteStatus(status?.id!);
|
||||
const { mutate: unfavouriteStatus } = useUnfavouriteStatus(status?.id!);
|
||||
const { mutate: reblogStatus } = useReblogStatus(status?.id!);
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(status?.id!);
|
||||
|
||||
const history = useHistory();
|
||||
const intl = useIntl();
|
||||
const instance = useInstance();
|
||||
@ -252,9 +257,9 @@ const Notification: React.FC<INotification> = (props) => {
|
||||
const handleHotkeyFavourite = useCallback((e?: KeyboardEvent) => {
|
||||
if (status && typeof status === 'object') {
|
||||
if (status.favourited) {
|
||||
dispatch(unfavourite(status));
|
||||
unfavouriteStatus();
|
||||
} else {
|
||||
dispatch(favourite(status));
|
||||
favouriteStatus();
|
||||
}
|
||||
}
|
||||
}, [status]);
|
||||
@ -263,15 +268,15 @@ const Notification: React.FC<INotification> = (props) => {
|
||||
if (status && typeof status === 'object') {
|
||||
const boostModal = settings.boostModal;
|
||||
if (status.reblogged) {
|
||||
dispatch(unreblog(status));
|
||||
unreblogStatus();
|
||||
} else {
|
||||
if (e?.shiftKey || !boostModal) {
|
||||
dispatch(reblog(status));
|
||||
reblogStatus(undefined);
|
||||
} else {
|
||||
openModal('BOOST', {
|
||||
statusId: status.id,
|
||||
onReblog: () => {
|
||||
dispatch(reblog(status));
|
||||
reblogStatus(undefined);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import { useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { type ComposeReplyAction, mentionCompose, replyCompose } from 'pl-fe/actions/compose';
|
||||
import { reblog, toggleFavourite, unreblog } from 'pl-fe/actions/interactions';
|
||||
import ScrollableList from 'pl-fe/components/scrollable-list';
|
||||
import StatusActionBar from 'pl-fe/components/status-action-bar';
|
||||
import Tombstone from 'pl-fe/components/tombstone';
|
||||
@ -16,6 +15,7 @@ import { HotKeys } from 'pl-fe/features/ui/components/hotkeys';
|
||||
import PendingStatus from 'pl-fe/features/ui/components/pending-status';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useFavouriteStatus, useReblogStatus, useUnfavouriteStatus, useUnreblogStatus } from 'pl-fe/queries/statuses/use-status-interactions';
|
||||
import { RootState } from 'pl-fe/store';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useSettingsStore } from 'pl-fe/stores/settings';
|
||||
@ -117,6 +117,11 @@ const Thread: React.FC<IThread> = ({
|
||||
const { openModal } = useModalsStore();
|
||||
const { settings } = useSettingsStore();
|
||||
|
||||
const { mutate: favouriteStatus } = useFavouriteStatus(status.id);
|
||||
const { mutate: unfavouriteStatus } = useUnfavouriteStatus(status.id);
|
||||
const { mutate: reblogStatus } = useReblogStatus(status.id);
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(status.id);
|
||||
|
||||
const getThread = useCallback(makeGetThread(), []);
|
||||
|
||||
const { ancestorsIds, descendantsIds } = useAppSelector((state) => getThread(state, status.id));
|
||||
@ -135,22 +140,21 @@ const Thread: React.FC<IThread> = ({
|
||||
};
|
||||
|
||||
const handleFavouriteClick = (status: SelectedStatus) => {
|
||||
dispatch(toggleFavourite(status));
|
||||
if (status.favourited) unfavouriteStatus();
|
||||
else favouriteStatus();
|
||||
};
|
||||
|
||||
const handleReplyClick = (status: ComposeReplyAction['status']) => dispatch(replyCompose(status));
|
||||
|
||||
const handleModalReblog = (status: Pick<SelectedStatus, 'id'>) => dispatch(reblog(status));
|
||||
|
||||
const handleReblogClick = (status: SelectedStatus, e?: React.MouseEvent) => {
|
||||
const boostModal = settings.boostModal;
|
||||
if (status.reblogged) {
|
||||
dispatch(unreblog(status));
|
||||
unreblogStatus();
|
||||
} else {
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
handleModalReblog(status);
|
||||
reblogStatus(undefined);
|
||||
} else {
|
||||
openModal('BOOST', { statusId: status.id, onReblog: () => handleModalReblog(status) });
|
||||
openModal('BOOST', { statusId: status.id, onReblog: () => reblogStatus(undefined) });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { importEntities } from 'pl-fe/actions/importer';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
@ -6,6 +6,8 @@ import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/queries/utils/minify-list';
|
||||
|
||||
import type { InteractionsAction } from 'pl-fe/actions/interactions';
|
||||
|
||||
const queryKey = {
|
||||
getDislikedBy: 'statusDislikes',
|
||||
getFavouritedBy: 'statusFavourites',
|
||||
@ -36,4 +38,117 @@ const useStatusReactions = (statusId: string, emoji?: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export { useStatusDislikes, useStatusFavourites, useStatusReactions, useStatusReblogs };
|
||||
const useFavouriteStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'favourite', statusId],
|
||||
mutationFn: () => client.statuses.favouriteStatus(statusId),
|
||||
onMutate: () => dispatch<InteractionsAction>({ type: 'FAVOURITE_REQUEST', statusId }),
|
||||
onError: () => dispatch<InteractionsAction>({ type: 'UNFAVOURITE_REQUEST', statusId }),
|
||||
onSettled: (status) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'statusFavourites', statusId] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUnfavouriteStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'favourite', statusId],
|
||||
mutationFn: () => client.statuses.unfavouriteStatus(statusId),
|
||||
onMutate: () => dispatch<InteractionsAction>({ type: 'UNFAVOURITE_REQUEST', statusId }),
|
||||
onError: () => dispatch<InteractionsAction>({ type: 'FAVOURITE_REQUEST', statusId }),
|
||||
onSettled: (status) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'statusFavourites', statusId] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useDislikeStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'dislike', statusId],
|
||||
mutationFn: () => client.statuses.dislikeStatus(statusId),
|
||||
onMutate: () => dispatch<InteractionsAction>({ type: 'DISLIKE_REQUEST', statusId }),
|
||||
onError: () => dispatch<InteractionsAction>({ type: 'UNDISLIKE_REQUEST', statusId }),
|
||||
onSettled: (status) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'statusDislikes', statusId] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUndislikeStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'dislike', statusId],
|
||||
mutationFn: () => client.statuses.undislikeStatus(statusId),
|
||||
onMutate: () => dispatch<InteractionsAction>({ type: 'UNDISLIKE_REQUEST', statusId }),
|
||||
onError: () => dispatch<InteractionsAction>({ type: 'DISLIKE_REQUEST', statusId }),
|
||||
onSettled: (status) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'statusDislikes', statusId] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useReblogStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'reblog', statusId],
|
||||
mutationFn: (visibility?: string) => client.statuses.reblogStatus(statusId, visibility),
|
||||
onMutate: () => dispatch<InteractionsAction>({ type: 'REBLOG_REQUEST', statusId }),
|
||||
onError: (error) => dispatch<InteractionsAction>({ type: 'REBLOG_FAIL', statusId, error }),
|
||||
onSettled: (status) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'statusReblogs', statusId] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUnreblogStatus = (statusId: string) => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['statuses', 'reblog', statusId],
|
||||
mutationFn: () => client.statuses.unreblogStatus(statusId),
|
||||
onMutate: () => dispatch<InteractionsAction>({ type: 'UNREBLOG_REQUEST', statusId }),
|
||||
onError: (error) => dispatch<InteractionsAction>({ type: 'UNREBLOG_FAIL', statusId, error }),
|
||||
onSettled: (status) => {
|
||||
dispatch(importEntities({ statuses: [status] }));
|
||||
queryClient.invalidateQueries({ queryKey: ['accountsLists', 'statusReblogs', statusId] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
useStatusDislikes,
|
||||
useStatusFavourites,
|
||||
useStatusReactions,
|
||||
useStatusReblogs,
|
||||
useFavouriteStatus,
|
||||
useUnfavouriteStatus,
|
||||
useDislikeStatus,
|
||||
useUndislikeStatus,
|
||||
useReblogStatus,
|
||||
useUnreblogStatus,
|
||||
};
|
||||
|
||||
@ -34,8 +34,6 @@ import {
|
||||
type FavouritesAction,
|
||||
} from 'pl-fe/actions/favourites';
|
||||
import {
|
||||
FAVOURITE_SUCCESS,
|
||||
UNFAVOURITE_SUCCESS,
|
||||
BOOKMARK_SUCCESS,
|
||||
UNBOOKMARK_SUCCESS,
|
||||
PIN_SUCCESS,
|
||||
@ -161,10 +159,6 @@ const statusLists = (state = initialState, action: BookmarksAction | EventsActio
|
||||
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 FAVOURITE_SUCCESS:
|
||||
return create(state, draft => prependOneToList(draft, 'favourites', action.status));
|
||||
case UNFAVOURITE_SUCCESS:
|
||||
return create(state, draft => removeOneFromList(draft, 'favourites', action.status));
|
||||
case BOOKMARK_SUCCESS:
|
||||
return create(state, draft => addBookmarkToLists(draft, action.status));
|
||||
case UNBOOKMARK_SUCCESS:
|
||||
|
||||
Reference in New Issue
Block a user