nicolium: some migrations to mutations, remove unused stuff

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-03-15 12:04:52 +01:00
parent 128de0aab9
commit 3fb923ed05
16 changed files with 132 additions and 150 deletions

View File

@ -351,5 +351,4 @@ export {
authLoggedIn,
fetchMe,
patchMe,
patchMeSuccess,
};

View File

@ -76,4 +76,4 @@ const preload = () => {
}
};
export { pleromaDecoder, decodeFromMarkup, preload };
export { preload };

View File

@ -15,11 +15,13 @@ import { shouldHaveCard } from '@/utils/status';
import { importEntities } from './importer';
import type { NormalizedStatus as Status } from '@/normalizers/status';
import type { useQueryClient } from '@tanstack/react-query';
import type { CreateStatusParams, Status as BaseStatus } from 'pl-api';
import type { IntlShape } from 'react-intl';
const incrementReplyCount = (
params: Pick<BaseStatus | CreateStatusParams, 'in_reply_to_id' | 'quote_id'>,
queryClient: ReturnType<typeof useQueryClient>,
) => {
if (params.in_reply_to_id) {
updateStatus(
@ -45,6 +47,7 @@ const incrementReplyCount = (
const decrementReplyCount = (
params: Pick<BaseStatus | CreateStatusParams, 'in_reply_to_id' | 'quote_id'>,
queryClient: ReturnType<typeof useQueryClient>,
) => {
if (params.in_reply_to_id) {
updateStatus(
@ -77,7 +80,7 @@ const createStatus = (
useContextStore.getState().actions.importPendingStatus(params.in_reply_to_id, idempotencyKey);
useTimelinesStore.getState().actions.importPendingStatus(params, idempotencyKey);
if (!editedId) {
incrementReplyCount(params);
incrementReplyCount(params, queryClient);
}
}
@ -145,7 +148,7 @@ const createStatus = (
useTimelinesStore.getState().actions.deletePendingStatus(idempotencyKey);
useContextStore.getState().actions.deletePendingStatus(params.in_reply_to_id, idempotencyKey);
if (!editedId) {
decrementReplyCount(params);
decrementReplyCount(params, queryClient);
}
throw error;
});
@ -183,67 +186,6 @@ const fetchStatus = (statusId: string, intl?: IntlShape) => {
});
};
const deleteStatus = (statusId: string, withRedraft = false) => {
if (!isLoggedIn()) return null;
const status = queryClient.getQueryData(queryKeys.statuses.show(statusId));
if (!status) return null;
const poll = status.poll_id
? queryClient.getQueryData(queryKeys.statuses.polls.show(status.poll_id))
: undefined;
decrementReplyCount(status);
return getClient()
.statuses.deleteStatus(statusId)
.then((source) => {
usePendingStatusesStore.getState().actions.deleteStatus(statusId);
useTimelinesStore.getState().actions.deleteStatus(statusId);
updateStatus(
statusId,
(s) => {
s.deleted = true;
},
queryClient,
);
if (withRedraft) {
useComposeStore.getState().actions.setComposeToStatus(status, poll, source, withRedraft);
useModalsStore.getState().actions.openModal('COMPOSE');
}
})
.catch(() => {
incrementReplyCount(status);
});
};
const deleteStatusFromGroup = (statusId: string, groupId: string) => {
if (!isLoggedIn()) return null;
const status = queryClient.getQueryData(queryKeys.statuses.show(statusId));
if (!status) return null;
decrementReplyCount(status);
return getClient()
.experimental.groups.deleteGroupStatus(statusId, groupId)
.then(() => {
usePendingStatusesStore.getState().actions.deleteStatus(statusId);
useTimelinesStore.getState().actions.deleteStatus(statusId);
updateStatus(
statusId,
(s) => {
s.deleted = true;
},
queryClient,
);
})
.catch(() => {
incrementReplyCount(status);
});
};
const muteStatus = (statusId: string) => {
if (!isLoggedIn()) return;
@ -283,7 +225,7 @@ export {
createStatus,
editStatus,
fetchStatus,
deleteStatus,
deleteStatusFromGroup,
toggleMuteStatus,
decrementReplyCount,
incrementReplyCount,
};

View File

@ -32,6 +32,7 @@ import {
useWrenchedTimeline,
} from '@/queries/timelines/use-timelines';
import { useSettings } from '@/stores/settings';
import { useStatusMeta } from '@/stores/status-meta';
import { selectChild } from '@/utils/scroll-utils';
import { hasActiveFilters, sortFilteredTimeline } from '@/utils/timeline-filter';
@ -296,9 +297,10 @@ interface ITimelineStatus {
const TimelineStatus: React.FC<ITimelineStatus> = (props): React.JSX.Element => {
const { id, isConnectedTop, isConnectedBottom } = props;
const { deleted } = useStatusMeta(id);
const statusQuery = useStatus(id, { withFilteredResults: true });
if (statusQuery.data?.deleted) {
if (deleted) {
return (
<div className='py-4 pb-8'>
<Tombstone id={id} onMoveUp={props.onMoveUp} onMoveDown={props.onMoveDown} deleted />

View File

@ -6,12 +6,7 @@ import { defineMessages, useIntl } from 'react-intl';
import { redactStatus } from '@/actions/admin';
import { useDeleteStatusModal, useToggleStatusSensitivityModal } from '@/actions/moderation';
import { changeSetting } from '@/actions/settings';
import {
deleteStatus,
deleteStatusFromGroup,
editStatus,
toggleMuteStatus,
} from '@/actions/statuses';
import { editStatus, toggleMuteStatus } from '@/actions/statuses';
import DropdownMenu from '@/components/dropdown-menu';
import StatusActionButton from '@/components/statuses/status-action-button';
import { useCurrentAccount } from '@/contexts/current-account-context';
@ -28,6 +23,11 @@ import { useGroupQuery } from '@/queries/groups/use-group';
import { useBlockGroupUserMutation } from '@/queries/groups/use-group-blocks';
import { useCustomEmojis } from '@/queries/instance/use-custom-emojis';
import { useTranslationLanguages } from '@/queries/instance/use-translation-languages';
import {
useDeleteStatus,
useDeleteStatusFromGroup,
type SelectedStatus,
} from '@/queries/statuses/use-status';
import {
useBookmarkStatus,
useDislikeStatus,
@ -56,7 +56,6 @@ import Popover from '../ui/popover';
import type { Menu } from '@/components/dropdown-menu';
import type { Emoji as EmojiType } from '@/features/emoji';
import type { UnauthorizedModalAction } from '@/modals/unauthorized-modal';
import type { SelectedStatus } from '@/queries/statuses/use-status';
import type { Me } from '@/stores/auth';
const messages = defineMessages({
@ -739,6 +738,11 @@ const MenuButton: React.FC<IMenuButton> = ({
const { mutate: pinStatus } = usePinStatus(status.id);
const { mutate: unpinStatus } = useUnpinStatus(status.id);
const { mutate: unblockAccount } = useUnblockAccountMutation(status.account_id);
const { mutate: deleteStatus } = useDeleteStatus(status.id);
const { mutate: deleteStatusFromGroup } = useDeleteStatusFromGroup(
status.id,
status.group_id as string,
);
const deleteStatusModal = useDeleteStatusModal(status.id);
const toggleStatusSensitivityModal = useToggleStatusSensitivityModal(status.id);
@ -788,7 +792,7 @@ const MenuButton: React.FC<IMenuButton> = ({
const doDeleteStatus = (withRedraft = false) => {
if (!deleteModal) {
deleteStatus(status.id, withRedraft);
deleteStatus(withRedraft);
} else {
openModal('CONFIRM', {
heading: intl.formatMessage(
@ -800,7 +804,7 @@ const MenuButton: React.FC<IMenuButton> = ({
confirm: intl.formatMessage(
withRedraft ? messages.redraftConfirm : messages.deleteConfirm,
),
onConfirm: () => deleteStatus(status.id, withRedraft),
onConfirm: () => deleteStatus(withRedraft),
});
}
};
@ -936,7 +940,7 @@ const MenuButton: React.FC<IMenuButton> = ({
}),
confirm: intl.formatMessage(messages.deleteConfirm),
onConfirm: () => {
deleteStatusFromGroup(status.id, group!.id);
deleteStatusFromGroup();
},
});
};

View File

@ -206,7 +206,7 @@ const Status: React.FC<IStatus> = React.memo((props) => {
const features = useFeatures();
const { toggleStatusesMediaHidden, unfilterStatus } = useStatusMetaActions();
const { showFiltered } = useStatusMeta(status.id);
const { deleted, showFiltered } = useStatusMeta(status.id);
const { openModal } = useModalsActions();
const { replyCompose, mentionCompose } = useComposeActions();
const { boostModal } = useSettings();
@ -521,7 +521,7 @@ const Status: React.FC<IStatus> = React.memo((props) => {
if (!status) return null;
if (status.deleted)
if (deleted)
return <Tombstone id={status.id} onMoveUp={onMoveUp} onMoveDown={onMoveDown} deleted />;
if (filtered && showFiltered !== true) {

View File

@ -56,25 +56,6 @@ const isAlphaNumeric = (c: string) => {
const validEmojiChar = (c: string) => isAlphaNumeric(c) || ['_', '-', '.'].includes(c);
const buildCustomEmojis = (customEmojis: Array<BaseCustomEmoji>) => {
const emojis: EmojiMart<EmojiMartCustom>[] = [];
customEmojis.forEach((emoji) => {
const shortcode = emoji.shortcode;
const url = emoji.static_url;
const name = shortcode.replace(':', '');
emojis.push({
id: name,
name,
keywords: [name],
skins: [{ src: url }],
});
});
return emojis;
};
const buildCustomEmojiCategories = (customEmojis: Array<BaseCustomEmoji>, intl?: IntlShape) => {
const emojiCategories: Record<string, EmojiMart<EmojiMartCustom>[]> = {};
@ -118,7 +99,6 @@ export {
type Emoji,
isCustomEmoji,
isNativeEmoji,
buildCustomEmojis,
buildCustomEmojiCategories,
validEmojiChar,
};

View File

@ -3,7 +3,6 @@ import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { useDeleteStatusModal, useToggleStatusSensitivityModal } from '@/actions/moderation';
import { deleteStatus } from '@/actions/statuses';
import VerificationBadge from '@/components/accounts/verification-badge';
import DropdownMenu, { type Menu as MenuType } from '@/components/dropdown-menu';
import Icon from '@/components/icon';
@ -17,6 +16,7 @@ import { useFeatures } from '@/hooks/use-features';
import { useOwnAccount } from '@/hooks/use-own-account';
import { useAccount } from '@/queries/accounts/use-account';
import { useChats } from '@/queries/chats';
import { useDeleteStatus } from '@/queries/statuses/use-status';
import {
useBookmarkStatus,
usePinStatus,
@ -128,6 +128,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
const { mutate: unbookmarkStatus } = useUnbookmarkStatus(status?.id!);
const { mutate: pinStatus } = usePinStatus(status?.id!);
const { mutate: unpinStatus } = useUnpinStatus(status?.id!);
const { mutate: deleteStatus } = useDeleteStatus(status?.id!);
const deleteStatusModal = useDeleteStatusModal(status?.id!);
const toggleStatusSensitivityModal = useToggleStatusSensitivityModal(status?.id!);
@ -209,7 +210,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
/>
),
confirm: <FormattedMessage id='confirmations.delete_event.confirm' defaultMessage='Delete' />,
onConfirm: () => deleteStatus(status.id),
onConfirm: () => deleteStatus(undefined),
});
};

View File

@ -6,6 +6,7 @@ import StatusContainer from '@/containers/status-container';
import PlaceholderStatus from '@/features/placeholder/components/placeholder-status';
import { useMinimalStatus } from '@/queries/statuses/use-status';
import { useReplyCount, useReplyToId } from '@/stores/contexts';
import { useStatusMeta } from '@/stores/status-meta';
import type { FilterContextType } from '@/queries/settings/use-filters';
@ -26,9 +27,9 @@ const ThreadStatus: React.FC<IThreadStatus> = (props): React.JSX.Element => {
const replyCount = useReplyCount(id);
const { data: statusData } = useMinimalStatus(id);
const isLoaded = Boolean(statusData);
const isDeleted = Boolean(statusData?.deleted);
const { deleted } = useStatusMeta(id);
if (isDeleted) {
if (deleted) {
return (
<div className='py-4 pb-8'>
<Tombstone id={id} onMoveUp={props.onMoveUp} onMoveDown={props.onMoveDown} deleted />

View File

@ -19,7 +19,7 @@ import { useComposeActions } from '@/stores/compose';
import { useThread } from '@/stores/contexts';
import { useModalsActions } from '@/stores/modals';
import { useSettings } from '@/stores/settings';
import { useStatusMetaActions } from '@/stores/status-meta';
import { useStatusMeta, useStatusMetaActions } from '@/stores/status-meta';
import { selectChild } from '@/utils/scroll-utils';
import { textForScreenReader } from '@/utils/status';
@ -50,6 +50,7 @@ const Thread = ({
const intl = useIntl();
const { replyCompose, mentionCompose } = useComposeActions();
const { deleted } = useStatusMeta(status.id);
const { expandStatuses, revealStatusesMedia, toggleStatusesMediaHidden } = useStatusMetaActions();
const { openModal } = useModalsActions();
const {
@ -238,7 +239,7 @@ const Thread = ({
if (id === status.id)
return (
<div className={clsx({ 'pb-4': hasDescendants })} key={status.id}>
{status.deleted ? (
{deleted ? (
<Tombstone
id={status.id}
onMoveUp={handleMoveUp}

View File

@ -1,28 +0,0 @@
import { Outlet } from '@tanstack/react-router';
import React from 'react';
import Layout from '@/components/ui/layout';
import { useCurrentAccount } from '@/contexts/current-account-context';
import LinkFooter from '@/features/ui/components/link-footer';
import { TrendsPanel, SignUpPanel } from '@/features/ui/util/async-components';
import { useFeatures } from '@/hooks/use-features';
const LandingLayout = () => {
const me = useCurrentAccount();
const features = useFeatures();
return (
<>
<Layout.Main className='space-y-3 pt-3 black:divide-gray-800 dark:divide-primary-800 sm:pt-0'>
<Outlet />
</Layout.Main>
<Layout.Aside>
{!me && <SignUpPanel />}
{features.trends && <TrendsPanel limit={5} />}
<LinkFooter />
</Layout.Aside>
</>
);
};
export { LandingLayout as default };

View File

@ -134,7 +134,6 @@ const normalizeStatus = (
poll_id: poll?.id ?? null,
group_id: group?.id ?? null,
expectsCard: false,
deleted: false,
...status,
quote_id: status.quote_id ?? null,
mentions,

View File

@ -1,12 +1,24 @@
import { useQueries, useQuery, type UseQueryResult } from '@tanstack/react-query';
import {
useMutation,
useQueries,
useQuery,
useQueryClient,
type UseQueryResult,
} from '@tanstack/react-query';
import { useMemo } from 'react';
import { importEntities } from '@/actions/importer';
import { decrementReplyCount, incrementReplyCount } from '@/actions/statuses';
import { useClient } from '@/hooks/use-client';
import { useFeatures } from '@/hooks/use-features';
import { normalizeStatus, type NormalizedStatus } from '@/normalizers/status';
import { useFilters } from '@/queries/settings/use-filters';
import { useComposeActions } from '@/stores/compose';
import { useContextsActions } from '@/stores/contexts';
import { useModalsActions } from '@/stores/modals';
import { usePendingStatusesActions } from '@/stores/pending-statuses';
import { useStatusMetaActions } from '@/stores/status-meta';
import { useTimelinesActions } from '@/stores/timelines';
import { checkFiltered } from '@/utils/filters';
import { useAccount } from '../accounts/use-account';
@ -170,11 +182,84 @@ const findStatuses = (
)
.map(([key, data]) => [key[1], data]);
const useDeleteStatus = (statusId: string) => {
const client = useClient();
const queryClient = useQueryClient();
const { markStatusDeleted } = useStatusMetaActions();
const { deleteStatus: deletePendingStatus } = usePendingStatusesActions();
const { deleteStatus: deleteStatusFromTimelines } = useTimelinesActions();
const { setComposeToStatus } = useComposeActions();
const { openModal } = useModalsActions();
return useMutation({
mutationFn: (_withRedraft?: boolean) => client.statuses.deleteStatus(statusId),
onMutate: () => {
const status = queryClient.getQueryData(queryKeys.statuses.show(statusId));
if (!status) return;
decrementReplyCount(status, queryClient);
},
onSuccess: (source, withRedraft) => {
const status = queryClient.getQueryData(queryKeys.statuses.show(statusId));
const poll = status?.poll_id
? queryClient.getQueryData(queryKeys.statuses.polls.show(status.poll_id))
: undefined;
deletePendingStatus(statusId);
deleteStatusFromTimelines(statusId);
markStatusDeleted(statusId);
if (withRedraft && status) {
setComposeToStatus(status, poll, source, withRedraft);
openModal('COMPOSE');
}
},
onError: () => {
const status = queryClient.getQueryData(queryKeys.statuses.show(statusId));
if (!status) return;
incrementReplyCount(status, queryClient);
},
});
};
const useDeleteStatusFromGroup = (statusId: string, groupId: string) => {
const client = useClient();
const queryClient = useQueryClient();
const { markStatusDeleted } = useStatusMetaActions();
const { deleteStatus: deletePendingStatus } = usePendingStatusesActions();
const { deleteStatus: deleteStatusFromTimelines } = useTimelinesActions();
return useMutation({
mutationFn: () => client.experimental.groups.deleteGroupStatus(statusId, groupId),
onMutate: () => {
const status = queryClient.getQueryData(queryKeys.statuses.show(statusId));
if (!status) return;
decrementReplyCount(status, queryClient);
},
onSuccess: () => {
deletePendingStatus(statusId);
deleteStatusFromTimelines(statusId);
markStatusDeleted(statusId);
},
onError: () => {
const status = queryClient.getQueryData(queryKeys.statuses.show(statusId));
if (!status) return;
incrementReplyCount(status, queryClient);
},
});
};
export {
useMinimalStatus,
useStatus,
useStatusContext,
useStatuses,
useDeleteStatus,
useDeleteStatusFromGroup,
findStatuses,
type MinifiedContext,
type SelectedStatus,

View File

@ -1,13 +0,0 @@
import type { DefaultError, UseMutationOptions } from '@tanstack/react-query';
// From https://github.com/TanStack/query/discussions/6096#discussioncomment-9685102
const mutationOptions = <
TData = unknown,
TError = DefaultError,
TVariables = void,
TContext = unknown,
>(
options: UseMutationOptions<TData, TError, TVariables, TContext>,
): UseMutationOptions<TData, TError, TVariables, TContext> => options;
export { mutationOptions };

View File

@ -12,6 +12,7 @@ type State = {
localTargetLanguage?: string;
showPollResults?: boolean;
showFiltered?: boolean;
deleted?: boolean;
}
>;
actions: {
@ -27,6 +28,7 @@ type State = {
setStatusLanguage: (statusId: string, language: string) => void;
toggleShowPollResults: (statusId: string) => void;
unfilterStatus: (statusId: string) => void;
markStatusDeleted: (statusId: string) => void;
};
};
@ -126,6 +128,13 @@ const useStatusMetaStore = create<State>()(
state.statuses[statusId].showFiltered = true;
});
},
markStatusDeleted: (statusId) => {
set((state: State) => {
if (!state.statuses[statusId]) state.statuses[statusId] = {};
state.statuses[statusId].deleted = true;
});
},
},
})),
);

View File

@ -29,4 +29,4 @@ const getBadges = (account: Pick<Account, '__meta'>) => {
return filterBadges(tags);
};
export { tagToBadge, badgeToTag, filterBadges, getTagDiff, getBadges };
export { tagToBadge, badgeToTag, getTagDiff, getBadges };