nicolium: add the remaining key types

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-02-26 19:50:46 +01:00
parent 953fdf8a01
commit c0b476dcf7
19 changed files with 153 additions and 104 deletions

View File

@ -11,7 +11,7 @@ import { STATUS_FETCH_SOURCE_FAIL, type StatusesAction } from './statuses';
import { deleteFromTimelines } from './timelines';
import type { AppDispatch, RootState } from '@/store';
import type { PleromaConfig, Poll } from 'pl-api';
import type { PleromaConfig } from 'pl-api';
const ADMIN_CONFIG_FETCH_SUCCESS = 'ADMIN_CONFIG_FETCH_SUCCESS' as const;
@ -140,7 +140,7 @@ const redactStatus = (statusId: string) => (dispatch: AppDispatch, getState: ()
const status = state.statuses[statusId];
const poll = status.poll_id
? queryClient.getQueryData<Poll>(queryKeys.statuses.polls.show(status.poll_id))
? queryClient.getQueryData(queryKeys.statuses.polls.show(status.poll_id))
: undefined;
return getClient(state)

View File

@ -10,7 +10,6 @@ import type {
Poll as BasePoll,
Relationship as BaseRelationship,
Status as BaseStatus,
GroupRelationship,
} from 'pl-api';
const STATUS_IMPORT = 'STATUS_IMPORT' as const;
@ -108,17 +107,14 @@ const importEntities =
if (!isEmpty(accounts)) {
for (const account of Object.values(accounts)) {
queryClient.setQueryData<BaseAccount>(queryKeys.accounts.show(account.id), account);
queryClient.setQueryData(queryKeys.accounts.show(account.id), account);
}
}
if (!isEmpty(groups))
for (const group of Object.values(groups)) {
queryClient.setQueryData<BaseGroup>(queryKeys.groups.show(group.id), group);
queryClient.setQueryData(queryKeys.groups.show(group.id), group);
if (group.relationship) {
queryClient.setQueryData<GroupRelationship>(
queryKeys.groupRelationships.show(group.id),
group.relationship,
);
queryClient.setQueryData(queryKeys.groupRelationships.show(group.id), group.relationship);
}
}
if (!isEmpty(polls)) {

View File

@ -24,13 +24,12 @@ import type {
Announcement,
AnnouncementReaction,
FollowRelationshipUpdate,
Relationship,
StreamingEvent,
} from 'pl-api';
const updateAnnouncementReactions = (reaction: AnnouncementReaction) => {
queryClient.setQueryData(queryKeys.announcements.all, (prevResult: Announcement[]) =>
prevResult.map((value) => {
queryClient.setQueryData(queryKeys.announcements.all, (prevResult) =>
prevResult?.map((value) => {
if (value.id !== reaction.announcement_id) return value;
return {
@ -42,7 +41,9 @@ const updateAnnouncementReactions = (reaction: AnnouncementReaction) => {
};
const updateAnnouncement = (announcement: Announcement) =>
queryClient.setQueryData(queryKeys.announcements.all, (prevResult: Announcement[]) => {
queryClient.setQueryData(queryKeys.announcements.all, (prevResult) => {
if (!prevResult) return;
let updated = false;
const result = prevResult.map((value) =>
@ -53,8 +54,8 @@ const updateAnnouncement = (announcement: Announcement) =>
});
const deleteAnnouncement = (announcementId: string) =>
queryClient.setQueryData(queryKeys.announcements.all, (prevResult: Announcement[]) =>
prevResult.filter((value) => value.id !== announcementId),
queryClient.setQueryData(queryKeys.announcements.all, (prevResult) =>
prevResult?.filter((value) => value.id !== announcementId),
);
const followStateToRelationship = (followState: FollowRelationshipUpdate['state']) => {
@ -77,7 +78,7 @@ const updateFollowRelationships =
const me = state.me;
if (update.follower.id === me) {
queryClient.setQueryData<Relationship>(
queryClient.setQueryData(
queryKeys.accountRelationships.show(update.following.id),
(relationship) =>
relationship

View File

@ -6,10 +6,10 @@ import HStack from '@/components/ui/hstack';
import Icon from '@/components/ui/icon';
import Text from '@/components/ui/text';
import type { Scrobble as ScrobbleEntity } from 'pl-api';
import type { MinifiedScrobble } from '@/queries/accounts/account-scrobble';
interface IScrobble {
scrobble: ScrobbleEntity;
scrobble: MinifiedScrobble;
}
const Scrobble: React.FC<IScrobble> = ({ scrobble }) => {

View File

@ -17,8 +17,6 @@ import { useModalsActions } from '@/stores/modals';
import { useIsSidebarOpen, useUiStoreActions } from '@/stores/ui';
import { isStandalone } from '@/utils/state';
import type { Group } from 'pl-api';
const messages = defineMessages({
home: { id: 'column.home', defaultMessage: 'Home' },
search: { id: 'column.search', defaultMessage: 'Search' },
@ -48,7 +46,7 @@ const ThumbNavigation: React.FC = React.memo((): React.JSX.Element => {
const handleOpenComposeModal = () => {
if (match?.params.groupId) {
const group = queryClient.getQueryData<Group>(queryKeys.groups.show(match.params.groupId));
const group = queryClient.getQueryData(queryKeys.groups.show(match.params.groupId));
if (group) groupComposeModal(group);
} else {
openModal('COMPOSE');

View File

@ -47,7 +47,6 @@ import { $createMentionNode } from '../nodes/mention-node';
import type { AutoSuggestion } from '@/components/autosuggest-input';
import type { Emoji } from '@/features/emoji';
import type { Account } from 'pl-api';
type QueryMatch = {
leadOffset: number;
@ -318,7 +317,7 @@ const AutosuggestPlugin = ({
(node as TextNode).setTextContent(`${suggestion} `);
node.select();
} else {
const account = queryClient.getQueryData<Account>(queryKeys.accounts.show(suggestion));
const account = queryClient.getQueryData(queryKeys.accounts.show(suggestion));
if (account) replaceMatch($createMentionNode(account));
}
}

View File

@ -1,21 +1,29 @@
import { useQuery } from '@tanstack/react-query';
import { Scrobble } from 'pl-api';
import { useClient } from '@/hooks/use-client';
import { useFeatures } from '@/hooks/use-features';
import { queryKeys } from '@/queries/keys';
const minifyScrobble = ({ account, ...scrobble }: Scrobble) => scrobble;
type MinifiedScrobble = ReturnType<typeof minifyScrobble>;
const useAccountScrobbleQuery = (accountId?: string) => {
const client = useClient();
const features = useFeatures();
return useQuery({
queryKey: queryKeys.scrobbles.show(accountId!),
queryFn: async () =>
(await client.accounts.getScrobbles(accountId!, { limit: 1 })).items[0] || null,
queryFn: async () => {
const scrobbles = await client.accounts.getScrobbles(accountId!, { limit: 1 });
return scrobbles.items.length > 0 ? minifyScrobble(scrobbles.items[0]) : null;
},
placeholderData: undefined,
enabled: () => !!accountId && features.scrobbles,
staleTime: 3 * 60 * 1000,
});
};
export { useAccountScrobbleQuery };
export { useAccountScrobbleQuery, type MinifiedScrobble };

View File

@ -11,7 +11,7 @@ const getAccounts = (): Array<Account> =>
.filter((account): account is Account => !!account && typeof account.id === 'string');
const selectAccount = (accountId: string) =>
queryClient.getQueryData<Account>(queryKeys.accounts.show(accountId));
queryClient.getQueryData(queryKeys.accounts.show(accountId));
const selectAccounts = (accountIds: Array<string>) =>
accountIds

View File

@ -27,7 +27,7 @@ const updateRelationship = (
changes: Partial<Relationship> | ((relationship: Relationship) => Relationship),
queryClient: ReturnType<typeof useQueryClient>,
) => {
const previousRelationship = queryClient.getQueryData<Relationship>(
const previousRelationship = queryClient.getQueryData(
queryKeys.accountRelationships.show(accountId),
);
if (!previousRelationship) return;

View File

@ -54,8 +54,8 @@ const useAnnouncements = () => {
client.announcements.addAnnouncementReaction(announcementId, name),
retry: false,
onMutate: ({ announcementId: id, name }) => {
queryClient.setQueryData(queryKeys.announcements.all, (prevResult: Announcement[]) =>
prevResult.map((value) =>
queryClient.setQueryData(queryKeys.announcements.all, (prevResult) =>
prevResult?.map((value) =>
value.id !== id
? value
: {
@ -66,8 +66,8 @@ const useAnnouncements = () => {
);
},
onError: (_, { announcementId: id, name }) => {
queryClient.setQueryData(queryKeys.announcements.all, (prevResult: Announcement[]) =>
prevResult.map((value) =>
queryClient.setQueryData(queryKeys.announcements.all, (prevResult) =>
prevResult?.map((value) =>
value.id !== id
? value
: {
@ -84,8 +84,8 @@ const useAnnouncements = () => {
client.announcements.deleteAnnouncementReaction(announcementId, name),
retry: false,
onMutate: ({ announcementId: id, name }) => {
queryClient.setQueryData(queryKeys.announcements.all, (prevResult: Announcement[]) =>
prevResult.map((value) =>
queryClient.setQueryData(queryKeys.announcements.all, (prevResult) =>
prevResult?.map((value) =>
value.id !== id
? value
: {
@ -96,8 +96,8 @@ const useAnnouncements = () => {
);
},
onError: (_, { announcementId: id, name }) => {
queryClient.setQueryData(queryKeys.announcements.all, (prevResult: Announcement[]) =>
prevResult.map((value) =>
queryClient.setQueryData(queryKeys.announcements.all, (prevResult) =>
prevResult?.map((value) =>
value.id !== id
? value
: {

View File

@ -111,11 +111,9 @@ const useMarkConversationRead = (conversationId: string) => {
onMutate: async () => {
await queryClient.cancelQueries({ queryKey: queryKeys.conversations.all });
const previous = queryClient.getQueryData<
InfiniteData<PaginatedResponse<MinifiedConversation>>
>(['conversations']);
const previous = queryClient.getQueryData(queryKeys.conversations.all);
updatePaginatedResponse<MinifiedConversation>(['conversations'], (items) =>
updatePaginatedResponse<MinifiedConversation>(queryKeys.conversations.all, (items) =>
items.map((item) => (item.id === conversationId ? { ...item, unread: false } : item)),
);

View File

@ -5,8 +5,6 @@ import { useFeatures } from '@/hooks/use-features';
import { queryKeys } from '../keys';
import type { DriveFolder } from 'pl-api';
const useDriveFolderQuery = (folderId?: string) => {
const client = useClient();
const features = useFeatures();
@ -45,9 +43,7 @@ const useUpdateDriveFolderMutation = (folderId: string) => {
return useMutation({
mutationKey: ['drive', 'folders'],
mutationFn: (name: string) => {
const oldFolder = queryClient.getQueryData<DriveFolder>(
queryKeys.drive.folders.show(folderId),
);
const oldFolder = queryClient.getQueryData(queryKeys.drive.folders.show(folderId));
if (oldFolder) {
previousParentId = oldFolder.parent_id;
} else {
@ -76,9 +72,7 @@ const useDeleteDriveFolderMutation = (folderId: string) => {
return useMutation({
mutationKey: ['drive', 'folders'],
mutationFn: () => {
const oldFolder = queryClient.getQueryData<DriveFolder>(
queryKeys.drive.folders.show(folderId),
);
const oldFolder = queryClient.getQueryData(queryKeys.drive.folders.show(folderId));
if (oldFolder) {
previousParentId = oldFolder.parent_id;
} else {
@ -110,9 +104,7 @@ const useMoveDriveFolderMutation = (folderId: string) => {
return useMutation({
mutationKey: ['drive', 'folders'],
mutationFn: (targetFolderId?: string) => {
const oldFolder = queryClient.getQueryData<DriveFolder>(
queryKeys.drive.folders.show(folderId),
);
const oldFolder = queryClient.getQueryData(queryKeys.drive.folders.show(folderId));
if (oldFolder) {
previousParentId = oldFolder.parent_id;
} else {

View File

@ -22,14 +22,9 @@ type Embed = {
const useEmbed = (url: string) => {
const client = useClient();
const getEmbed = async () => {
const data = await client.oembed.getOembed(url);
return data;
};
return useQuery<Embed>({
queryKey: queryKeys.embed.show(url),
queryFn: getEmbed,
queryFn: () => client.oembed.getOembed(url),
});
};

View File

@ -6,7 +6,7 @@ import { queryClient } from '../client';
import { queryKeys } from '../keys';
import { makePaginatedResponseQuery } from '../utils/make-paginated-response-query';
const useFollowedTags = makePaginatedResponseQuery(['followedTags'], (client) =>
const useFollowedTags = makePaginatedResponseQuery(queryKeys.followedTags.all, (client) =>
client.myAccount.getFollowedTags(),
);

View File

@ -1,8 +1,16 @@
import { MinifiedInteractionRequest } from './statuses/use-interaction-requests';
import type { MinifiedScrobble } from './accounts/account-scrobble';
import type { FilterType } from './notifications/use-notifications';
import type { DraftStatus } from './statuses/use-draft-statuses';
import type { MinifiedStatusEdit } from './statuses/use-status-history';
import type { MinifiedEmojiReaction } from './statuses/use-status-interactions';
import type { MinifiedSuggestion } from './trends/use-suggested-accounts';
import type { MinifiedAdminAccount, MinifiedAdminReport } from './utils/minify-list';
import type {
MinifiedAdminAccount,
MinifiedAdminReport,
MinifiedConversation,
} from './utils/minify-list';
import type { ChatMessage } from '@/normalizers/chat-message';
import type { DataTag, InfiniteData } from '@tanstack/react-query';
import type {
@ -10,16 +18,23 @@ import type {
AdminAnnouncement,
AdminCohort,
AdminDimension,
AdminDimensionKey,
AdminDomain,
AdminGetAccountsParams,
AdminGetDimensionsParams,
AdminGetMeasuresParams,
AdminGetReportsParams,
AdminMeasure,
AdminMeasureKey,
AdminModerationLogEntry,
AdminRelay,
AdminRule,
Announcement,
Antenna,
Backup,
BookmarkFolder,
Chat,
Circle,
CredentialAccount,
CustomEmoji,
DriveFile,
@ -28,14 +43,18 @@ import type {
Group,
GroupRelationship,
GroupRole,
InteractionPolicies,
List,
Location,
Marker,
NotificationGroup,
OauthToken,
PaginatedResponse,
PlApiClient,
Poll,
Relationship,
RssFeed,
ScheduledStatus,
Tag,
Translation,
TrendsLink,
@ -314,11 +333,16 @@ const admin = {
['admin', 'moderation_log'],
InfiniteData<PaginatedResponse<AdminModerationLogEntry>>
>,
dimensions: (keys: string[], params?: AdminGetDimensionsParams) => {
dimensions: (keys: Array<AdminDimensionKey>, params?: AdminGetDimensionsParams) => {
const key = ['admin', 'dimensions', keys, params] as const;
return key as TaggedKey<typeof key, Array<AdminDimension>>;
},
measures: (keys: string[], startAt: string, endAt: string, params?: AdminGetMeasuresParams) => {
measures: (
keys: Array<AdminMeasureKey>,
startAt: string,
endAt: string,
params?: AdminGetMeasuresParams,
) => {
const key = ['admin', 'measures', keys, startAt, endAt, params] as const;
return key as TaggedKey<typeof key, Array<AdminMeasure>>;
},
@ -388,22 +412,36 @@ const timelines = {
const timelineIds = {
root: ['timelineIds'] as const,
accountMedia: (accountId: string) =>
['timelineIds', `account:${accountId}:with_replies:media`] as const,
groupMedia: (groupId: string) => ['timelineIds', `group:${groupId}:media`] as const,
accountMedia: (accountId: string) => {
const key = ['timelineIds', `account:${accountId}:with_replies:media`] as const;
return key as TaggedKey<typeof key, InfiniteData<PaginatedResponse<string>>>;
},
groupMedia: (groupId: string) => {
const key = ['timelineIds', `group:${groupId}:media`] as const;
return key as TaggedKey<typeof key, InfiniteData<PaginatedResponse<string>>>;
},
};
const settings = {
root: ['settings'] as const,
mfa: ['settings', 'mfa'] as const,
backups: ['settings', 'backups'] as const,
accountAliases: ['settings', 'accountAliases'] as const,
domainBlocks: ['settings', 'domainBlocks'] as const,
mfa: ['settings', 'mfa'] as TaggedKey<
['settings', 'mfa'],
Awaited<ReturnType<InstanceType<typeof PlApiClient>['settings']['mfa']['getMfaSettings']>>
>,
backups: ['settings', 'backups'] as TaggedKey<['settings', 'backups'], Array<Backup>>,
accountAliases: ['settings', 'accountAliases'] as TaggedKey<
['settings', 'accountAliases'],
Array<string>
>,
domainBlocks: ['settings', 'domainBlocks'] as TaggedKey<
['settings', 'domainBlocks'],
Array<string>
>,
};
const interactionPolicies = {
root: ['interactionPolicies'] as const,
all: ['interactionPolicies'] as const,
all: ['interactionPolicies'] as TaggedKey<['interactionPolicies'], InteractionPolicies>,
};
const filters = {
@ -443,72 +481,106 @@ const drive = {
const hashtags = {
root: ['hashtags'] as const,
show: (tag: string) => ['hashtags', tag] as const,
show: (tag: string) => {
const key = ['hashtags', tag] as const;
return key as TaggedKey<typeof key, Tag>;
},
};
const followedTags = {
root: ['followedTags'] as const,
all: ['followedTags'] as const,
all: ['followedTags'] as TaggedKey<['followedTags'], InfiniteData<PaginatedResponse<Tag>>>,
};
const conversations = {
root: ['conversations'] as const,
all: ['conversations'] as const,
all: ['conversations'] as TaggedKey<
['conversations'],
InfiniteData<PaginatedResponse<MinifiedConversation>>
>,
};
const announcements = {
root: ['announcements'] as const,
all: ['announcements'] as const,
all: ['announcements'] as TaggedKey<['announcements'], Array<Announcement>>,
};
const scrobbles = {
root: ['scrobbles'] as const,
show: (accountId: string) => ['scrobbles', accountId] as const,
show: (accountId: string) => {
const key = ['scrobbles', accountId] as const;
return key as TaggedKey<typeof key, MinifiedScrobble | null>;
},
};
const lists = {
root: ['lists'] as const,
all: ['lists'] as const,
forAccount: (accountId: string) => ['lists', 'forAccount', accountId] as const,
all: ['lists'] as TaggedKey<['lists'], Array<List>>,
forAccount: (accountId: string) => {
const key = ['lists', 'forAccount', accountId] as const;
return key as TaggedKey<typeof key, Array<List>>;
},
};
const circles = {
root: ['circles'] as const,
all: ['circles'] as const,
all: ['circles'] as TaggedKey<['circles'], Array<Circle>>,
};
const antennas = {
root: ['antennas'] as const,
all: ['antennas'] as TaggedKey<['antennas'], Array<string>>,
domains: (antennaId: string) => ['antennas', antennaId, 'domains'] as const,
keywords: (antennaId: string) => ['antennas', antennaId, 'keywords'] as const,
tags: (antennaId: string) => ['antennas', antennaId, 'tags'] as const,
all: ['antennas'] as TaggedKey<['antennas'], Array<Antenna>>,
domains: (antennaId: string) => {
const key = ['antennas', antennaId, 'domains'] as const;
return key as TaggedKey<typeof key, { domains: Array<string>; exclude_domains: Array<string> }>;
},
keywords: (antennaId: string) => {
const key = ['antennas', antennaId, 'keywords'] as const;
return key as TaggedKey<
typeof key,
{ keywords: Array<string>; exclude_keywords: Array<string> }
>;
},
tags: (antennaId: string) => {
const key = ['antennas', antennaId, 'tags'] as const;
return key as TaggedKey<typeof key, { tags: Array<string>; exclude_tags: Array<string> }>;
},
};
const bookmarkFolders = {
root: ['bookmarkFolders'] as const,
all: ['bookmarkFolders'] as const,
forStatus: (statusId: string) => ['bookmarkFolders', 'status', statusId] as const,
all: ['bookmarkFolders'] as TaggedKey<['bookmarkFolders'], Array<BookmarkFolder>>,
forStatus: (statusId: string) => {
const key = ['bookmarkFolders', 'status', statusId] as const;
return key as TaggedKey<typeof key, Array<BookmarkFolder>>;
},
};
const draftStatuses = {
root: ['draftStatuses'] as const,
all: ['draftStatuses'] as const,
all: ['draftStatuses'] as TaggedKey<['draftStatuses'], Record<string, DraftStatus>>,
};
const scheduledStatuses = {
root: ['scheduledStatuses'] as const,
all: ['scheduledStatuses'] as const,
all: ['scheduledStatuses'] as TaggedKey<['scheduledStatuses'], Array<ScheduledStatus>>,
};
const interactionRequests = {
root: ['interactionRequests'] as const,
all: ['interactionRequests'] as const,
all: ['interactionRequests'] as TaggedKey<
['interactionRequests'],
InfiniteData<PaginatedResponse<MinifiedInteractionRequest>>
>,
};
const embed = {
root: ['embed'] as const,
show: (url: string) => ['embed', url] as const,
show: (url: string) =>
['embed', url] as TaggedKey<
['embed', string],
Awaited<ReturnType<PlApiClient['oembed']['getOembed']>>
>,
};
const rssFeedSubscriptions = {

View File

@ -35,7 +35,6 @@ import { minifyGroupedNotifications } from '../utils/minify-list';
import type {
GetGroupedNotificationsParams,
Marker,
Notification,
NotificationGroup,
PaginatedResponse,
@ -233,7 +232,7 @@ const useMarkNotificationsReadMutation = () => {
mutationFn: async (lastReadId?: string | null) => {
if (!lastReadId) return;
const currentMarker = queryClient.getQueryData<Marker>(queryKeys.markers.notifications);
const currentMarker = queryClient.getQueryData(queryKeys.markers.notifications);
if (currentMarker && compareId(currentMarker.last_read_id, lastReadId) >= 0) {
return;
}

View File

@ -43,9 +43,7 @@ const useFilter = (filterId?: string) => {
},
enabled: !!filterId,
placeholderData: () =>
queryClient
.getQueryData<Array<Filter>>(['filters'])
?.find((filter) => filter.id === filterId),
queryClient.getQueryData(queryKeys.filters.all)?.find((filter) => filter.id === filterId),
});
};

View File

@ -95,8 +95,7 @@ const usePersistDraftStatus = () => {
draft_id: compose.draftId ?? crypto.randomUUID(),
};
const drafts =
queryClient.getQueryData<Record<string, DraftStatus>>(queryKeys.draftStatuses.all) ?? {};
const drafts = queryClient.getQueryData(queryKeys.draftStatuses.all) ?? {};
const newDrafts: Record<string, DraftStatus> = create(drafts, (oldDrafts) => {
oldDrafts[draft.draft_id] = v.parse(draftStatusSchema, draft);
@ -108,8 +107,7 @@ const usePersistDraftStatus = () => {
};
const cancelDraftStatus = (queryClient: QueryClient, accountUrl: string, draftId: string) => {
const drafts =
queryClient.getQueryData<Record<string, DraftStatus>>(queryKeys.draftStatuses.all) ?? {};
const drafts = queryClient.getQueryData(queryKeys.draftStatuses.all) ?? {};
const newDrafts: Record<string, DraftStatus> = create(drafts, (oldDrafts) => {
delete oldDrafts[draftId];

View File

@ -8,8 +8,7 @@ import { queryKeys } from '@/queries/keys';
import { compareDate } from './comparators';
import { appendPageItem, flattenPages, sortQueryData, updatePageItem } from './queries';
import type { InfiniteData } from '@tanstack/react-query';
import type { Chat, PaginatedResponse } from 'pl-api';
import type { Chat } from 'pl-api';
/**
* Update the Chat entity inside the ChatSearch query.
@ -34,9 +33,7 @@ const reOrderChatListItems = () => {
* @returns Boolean
*/
const checkIfChatExists = (chatId: string) => {
const currentChats = flattenPages(
queryClient.getQueryData<InfiniteData<PaginatedResponse<Chat>>>(queryKeys.chats.search),
);
const currentChats = flattenPages(queryClient.getQueryData(queryKeys.chats.search));
return currentChats?.find((chat: Chat) => chat.id === chatId);
};
@ -74,9 +71,7 @@ const updateChatListItem = (newChat: Chat) => {
/** Get unread chats count. */
const getUnreadChatsCount = (): number => {
const chats = flattenPages(
queryClient.getQueryData<InfiniteData<PaginatedResponse<Chat>>>(queryKeys.chats.search),
);
const chats = flattenPages(queryClient.getQueryData(queryKeys.chats.search));
return sumBy(chats, (chat) => chat.unread);
};