Migrate to external library for interacting with API

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2024-08-04 16:09:52 +02:00
parent 963ffb3d45
commit 4dfdfcccd3
137 changed files with 1136 additions and 2094 deletions

View File

@ -1,7 +1,7 @@
import { useMutation } from '@tanstack/react-query';
import { patchMeSuccess } from 'soapbox/actions/me';
import { useApi, useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import { useAppDispatch, useClient, useOwnAccount } from 'soapbox/hooks';
import toast from 'soapbox/toast';
type IAccount = {
@ -34,14 +34,11 @@ type UpdateCredentialsData = {
const useUpdateCredentials = () => {
const { account } = useOwnAccount();
const api = useApi();
const client = useClient();
const dispatch = useAppDispatch();
return useMutation({
mutationFn: (data: UpdateCredentialsData) => api('/api/v1/accounts/update_credentials', {
method: 'PATCH',
body: JSON.stringify(data),
}),
mutationFn: (data: UpdateCredentialsData) => client.accounts.updateCredentials(data),
onMutate(variables) {
const cachedAccount = account;
dispatch(patchMeSuccess({ ...account, ...variables }));
@ -49,7 +46,7 @@ const useUpdateCredentials = () => {
return { cachedAccount };
},
onSuccess(response) {
dispatch(patchMeSuccess(response.json));
dispatch(patchMeSuccess(response));
toast.success('Chat Settings updated successfully');
},
onError(_error, _variables, context: any) {

View File

@ -5,7 +5,7 @@ import { importFetchedAccount, importFetchedAccounts } from 'soapbox/actions/imp
import { getNextLink } from 'soapbox/api';
import { ChatWidgetScreens, useChatContext } from 'soapbox/contexts/chat-context';
import { useStatContext } from 'soapbox/contexts/stat-context';
import { useApi, useAppDispatch, useAppSelector, useFeatures, useLoggedIn, useOwnAccount } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useClient, useFeatures, useLoggedIn, useOwnAccount } from 'soapbox/hooks';
import { normalizeChatMessage } from 'soapbox/normalizers';
import { ChatMessage } from 'soapbox/types/entities';
import { reOrderChatListItems } from 'soapbox/utils/chats';
@ -37,13 +37,13 @@ const ChatKeys = {
};
const useChatMessages = (chat: IChat) => {
const api = useApi();
const client = useClient();
const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account.id, 'blocked_by']));
const getChatMessages = async (chatId: string, pageParam?: any): Promise<PaginatedResult<ChatMessage>> => {
const nextPageLink = pageParam?.link;
const uri = nextPageLink || `/api/v1/pleroma/chats/${chatId}/messages`;
const response = await api<any[]>(uri);
const response = await client.request<any[]>(uri);
const { json: data } = response;
const link = getNextLink(response);
@ -82,7 +82,7 @@ const useChatMessages = (chat: IChat) => {
};
const useChats = () => {
const api = useApi();
const client = useClient();
const dispatch = useAppDispatch();
const features = useFeatures();
const { setUnreadChatsCount } = useStatContext();
@ -90,10 +90,9 @@ const useChats = () => {
const { me } = useLoggedIn();
const getChats = async (pageParam?: any): Promise<PaginatedResult<IChat>> => {
const endpoint = features.chatsV2 ? '/api/v2/pleroma/chats' : '/api/v1/pleroma/chats';
const nextPageLink = pageParam?.link;
const uri = nextPageLink || endpoint;
const response = await api<IChat[]>(uri);
const uri = nextPageLink || '/api/v2/pleroma/chats';
const response = await client.request<IChat[]>(uri);
const { json: data } = response;
const link = getNextLink(response);
@ -134,19 +133,20 @@ const useChats = () => {
data,
};
const getOrCreateChatByAccountId = (accountId: string) => api<IChat>(`/api/v1/pleroma/chats/by-account-id/${accountId}`, { method: 'POST' });
const getOrCreateChatByAccountId = (accountId: string) =>
client.request<IChat>(`/api/v1/pleroma/chats/by-account-id/${accountId}`, { method: 'POST' });
return { chatsQuery, getOrCreateChatByAccountId };
};
const useChat = (chatId?: string) => {
const api = useApi();
const client = useClient();
const dispatch = useAppDispatch();
const fetchRelationships = useFetchRelationships();
const getChat = async () => {
if (chatId) {
const { json: data } = await api(`/api/v1/pleroma/chats/${chatId}`);
const { json: data } = await client.request(`/api/v1/pleroma/chats/${chatId}`);
fetchRelationships.mutate({ accountIds: [data.account.id] });
dispatch(importFetchedAccount(data.account));
@ -165,15 +165,14 @@ const useChat = (chatId?: string) => {
const useChatActions = (chatId: string) => {
const { account } = useOwnAccount();
const api = useApi();
// const dispatch = useAppDispatch();
const client = useClient();
const { setUnreadChatsCount } = useStatContext();
const { chat, changeScreen } = useChatContext();
const markChatAsRead = async (lastReadId: string) =>
api<IChat>(`/api/v1/pleroma/chats/${chatId}/read`, { body: JSON.stringify({ last_read_id: lastReadId }) })
client.request<IChat>(`/api/v1/pleroma/chats/${chatId}/read`, { body: { last_read_id: lastReadId } })
.then(({ json: data }) => {
updatePageItem(['chats', 'search'], data, (o, n) => o.id === n.id);
const queryData = queryClient.getQueryData<InfiniteData<PaginatedResult<unknown>>>(['chats', 'search']);
@ -194,14 +193,10 @@ const useChatActions = (chatId: string) => {
.catch(() => null);
const createChatMessage = useMutation({
mutationFn: ({ chatId, content, mediaIds }: { chatId: string; content: string; mediaIds?: string[] }) =>
api<ChatMessage>(`/api/v1/pleroma/chats/${chatId}/messages`, {
mutationFn: ({ chatId, content, mediaId }: { chatId: string; content: string; mediaId?: string }) =>
client.request<ChatMessage>(`/api/v1/pleroma/chats/${chatId}/messages`, {
method: 'POST',
body: JSON.stringify({
content,
media_id: (mediaIds && mediaIds.length === 1) ? mediaIds[0] : undefined, // Pleroma backwards-compat
media_ids: mediaIds,
}),
body: { content, media_id: mediaId },
}),
retry: false,
onMutate: async (variables) => {
@ -260,10 +255,10 @@ const useChatActions = (chatId: string) => {
},
});
const deleteChatMessage = (chatMessageId: string) =>
api<IChat>(`/api/v1/pleroma/chats/${chatId}/messages/${chatMessageId}`, { method: 'DELETE' });
client.request<IChat>(`/api/v1/pleroma/chats/${chatId}/messages/${chatMessageId}`, { method: 'DELETE' });
const deleteChat = useMutation({
mutationFn: () => api<IChat>(`/api/v1/pleroma/chats/${chatId}`, { method: 'DELETE' }),
mutationFn: () => client.request<IChat>(`/api/v1/pleroma/chats/${chatId}`, { method: 'DELETE' }),
onSuccess() {
changeScreen(ChatWidgetScreens.INBOX);
queryClient.invalidateQueries({ queryKey: ChatKeys.chatMessages(chatId) });

View File

@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import { useApi } from 'soapbox/hooks';
import { useClient } from 'soapbox/hooks';
type Embed = {
type: string;
@ -11,18 +11,18 @@ type Embed = {
provider_url: string;
cache_age: number;
html: string;
width: number;
height: number;
width: number | null;
height: number | null;
}
/** Fetch OEmbed information for a status by its URL. */
// https://github.com/mastodon/mastodon/blob/main/app/controllers/api/oembed_controller.rb
// https://github.com/mastodon/mastodon/blob/main/app/serializers/oembed_serializer.rb
const useEmbed = (url: string) => {
const api = useApi();
const client = useClient();
const getEmbed = async() => {
const { json: data } = await api('/api/oembed', { params: { url } });
const getEmbed = async () => {
const data = await client.oembed.getOembed(url);
return data;
};

View File

@ -1,17 +1,17 @@
import { useMutation } from '@tanstack/react-query';
import { fetchRelationshipsFail, fetchRelationshipsSuccess } from 'soapbox/actions/accounts';
import { useApi, useAppDispatch } from 'soapbox/hooks';
import { useAppDispatch, useClient } from 'soapbox/hooks';
const useFetchRelationships = () => {
const api = useApi();
const client = useClient();
const dispatch = useAppDispatch();
return useMutation({
mutationFn: ({ accountIds }: { accountIds: string[]}) => {
const ids = accountIds.map((id) => `id[]=${id}`).join('&');
return api(`/api/v1/accounts/relationships?${ids}`);
return client.request(`/api/v1/accounts/relationships?${ids}`);
},
onSuccess(response) {
dispatch(fetchRelationshipsSuccess(response.json));

View File

@ -1,51 +1,37 @@
import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query';
import { getNextLink } from 'soapbox/api';
import { useApi } from 'soapbox/hooks';
import { Account } from 'soapbox/types/entities';
import { flattenPages, PaginatedResult } from 'soapbox/utils/queries';
import { useClient } from 'soapbox/hooks';
import type { Account } from 'pl-api';
const useAccountSearch = (q: string) => {
const api = useApi();
const client = useClient();
const getAccountSearch = async(q: string, pageParam: { link?: string }): Promise<PaginatedResult<Account>> => {
const nextPageLink = pageParam?.link;
const uri = nextPageLink || '/api/v1/accounts/search';
const response = await api(uri, {
params: {
q,
limit: 10,
followers: true,
},
const getAccountSearch = async(q: string): Promise<Account[]> => {
const response = await client.accounts.searchAccounts(q, {
limit: 10,
following: true,
offset: data?.length,
});
const { json: data } = response;
const link = getNextLink(response);
const hasMore = !!link;
return {
result: data,
link,
hasMore,
};
return response;
};
const queryInfo = useInfiniteQuery({
queryKey: ['search', 'accounts', q],
queryFn: ({ pageParam }) => getAccountSearch(q, pageParam),
queryFn: () => getAccountSearch(q),
placeholderData: keepPreviousData,
initialPageParam: { link: undefined as string | undefined },
getNextPageParam: (config) => {
if (config.hasMore) {
return { link: config.link };
initialPageParam: {},
getNextPageParam: () => {
if (queryInfo.data[queryInfo.data.length - 1].length !== 10) {
return {};
}
return undefined;
},
});
const data = flattenPages(queryInfo.data);
const data = queryInfo.data?.pages.flat();
return {
...queryInfo,

View File

@ -1,71 +1,37 @@
import { useInfiniteQuery, useMutation, keepPreviousData } from '@tanstack/react-query';
import { useMutation, keepPreviousData, useQuery } from '@tanstack/react-query';
import { fetchRelationships } from 'soapbox/actions/accounts';
import { importFetchedAccounts } from 'soapbox/actions/importer';
import { getNextLink } from 'soapbox/api';
import { useApi, useAppDispatch } from 'soapbox/hooks';
import { useAppDispatch, useClient } from 'soapbox/hooks';
import { PaginatedResult, removePageItem } from '../utils/queries';
import type { IAccount } from './accounts';
type Suggestion = {
source: 'staff';
account: IAccount;
}
type Result = {
account: string;
}
type PageParam = {
link?: string;
}
import { removePageItem } from '../utils/queries';
const SuggestionKeys = {
suggestions: ['suggestions'] as const,
};
const useSuggestions = () => {
const api = useApi();
const client = useClient();
const dispatch = useAppDispatch();
const getV2Suggestions = async (pageParam: PageParam): Promise<PaginatedResult<Result>> => {
const endpoint = pageParam?.link || '/api/v2/suggestions';
const response = await api<Suggestion[]>(endpoint);
const hasMore = !!response.headers.get('link');
const nextLink = getNextLink(response);
const getSuggestions = async () => {
const response = await client.accounts.getSuggestions();
const accounts = response.json.map(({ account }) => account);
const accounts = response.map(({ account }) => account);
const accountIds = accounts.map((account) => account.id);
dispatch(importFetchedAccounts(accounts));
dispatch(fetchRelationships(accountIds));
return {
result: response.json.map(x => ({ ...x, account: x.account.id })),
link: nextLink,
hasMore,
};
return response.map(x => ({ ...x, account: x.account.id }));
};
const result = useInfiniteQuery({
const result = useQuery({
queryKey: SuggestionKeys.suggestions,
queryFn: ({ pageParam }: any) => getV2Suggestions(pageParam),
queryFn: () => getSuggestions(),
placeholderData: keepPreviousData,
initialPageParam: { nextLink: undefined },
getNextPageParam: (config) => {
if (config?.hasMore) {
return { nextLink: config?.link };
}
return undefined;
},
});
const data: any = result.data?.pages.reduce<Suggestion[]>(
(prev: any, curr: any) => [...prev, ...curr.result],
[],
);
const data = result.data;
return {
...result,
@ -74,10 +40,10 @@ const useSuggestions = () => {
};
const useDismissSuggestion = () => {
const api = useApi();
const client = useClient();
return useMutation({
mutationFn: (accountId: string) => api(`/api/v1/suggestions/${accountId}`, { method: 'DELETE' }),
mutationFn: (accountId: string) => client.accounts.dismissSuggestions(accountId),
onMutate(accountId: string) {
removePageItem(SuggestionKeys.suggestions, accountId, (o: any, n: any) => o.account === n);
},
@ -85,45 +51,27 @@ const useDismissSuggestion = () => {
};
const useOnboardingSuggestions = () => {
const api = useApi();
const client = useClient();
const dispatch = useAppDispatch();
const getV2Suggestions = async (pageParam: any): Promise<{ data: Suggestion[]; link: string | undefined; hasMore: boolean }> => {
const link = pageParam?.link || '/api/v2/suggestions';
const response = await api<Suggestion[]>(link);
const hasMore = !!response.headers.get('link');
const nextLink = getNextLink(response);
const getSuggestions = async () => {
const response = await client.accounts.getSuggestions();
const accounts = response.json.map(({ account }) => account);
const accounts = response.map(({ account }) => account);
const accountIds = accounts.map((account) => account.id);
dispatch(importFetchedAccounts(accounts));
dispatch(fetchRelationships(accountIds));
return {
data: response.json,
link: nextLink,
hasMore,
};
return response;
};
const result = useInfiniteQuery({
const result = useQuery({
queryKey: ['suggestions', 'v2'],
queryFn: ({ pageParam }) => getV2Suggestions(pageParam),
queryFn: () => getSuggestions(),
placeholderData: keepPreviousData,
initialPageParam: { link: undefined as string | undefined },
getNextPageParam: (config) => {
if (config.hasMore) {
return { link: config.link };
}
return undefined;
},
});
const data = result.data?.pages.reduce<Suggestion[]>(
(prev: Suggestion[], curr) => [...prev, ...curr.data],
[],
);
const data = result.data;
return {
...result,

View File

@ -1,17 +1,17 @@
import { useQuery } from '@tanstack/react-query';
import { fetchTrendsSuccess } from 'soapbox/actions/trends';
import { useApi, useAppDispatch } from 'soapbox/hooks';
import { useAppDispatch, useClient } from 'soapbox/hooks';
import { normalizeTag } from 'soapbox/normalizers';
import type { Tag } from 'soapbox/types/entities';
const useTrends = () => {
const api = useApi();
const dispatch = useAppDispatch();
const client = useClient();
const getTrends = async() => {
const { json: data } = await api<any[]>('/api/v1/trends');
const data = await client.trends.getTrendingTags();
dispatch(fetchTrendsSuccess(data));