Remove Truth Social-specific features

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2024-04-28 14:50:23 +02:00
parent 5ba66f79ba
commit 0308aec65b
163 changed files with 312 additions and 5471 deletions

View File

@ -26,12 +26,10 @@ export type IAccount = {
url: string;
username: string;
verified: boolean;
website: string;
}
type UpdateCredentialsData = {
accepts_chat_messages?: boolean;
chats_onboarded?: boolean;
}
const useUpdateCredentials = () => {

View File

@ -7,13 +7,11 @@ import { buildAccount, buildRelationship } from 'soapbox/jest/factory';
import { createTestStore, mockStore, queryClient, renderHook, rootState, waitFor } from 'soapbox/jest/test-helpers';
import { normalizeChatMessage } from 'soapbox/normalizers';
import { Store } from 'soapbox/store';
import { ChatMessage } from 'soapbox/types/entities';
import { flattenPages } from 'soapbox/utils/queries';
import { ChatKeys, IChat, isLastMessage, useChat, useChatActions, useChatMessages, useChats } from './chats';
import { ChatKeys, IChat, useChat, useChatActions, useChatMessages, useChats } from './chats';
const chat: IChat = {
accepted: true,
account: buildAccount({
username: 'username',
verified: true,
@ -23,15 +21,9 @@ const chat: IChat = {
avatar_static: 'avatar',
display_name: 'my name',
}),
chat_type: 'direct',
created_at: '2020-06-10T02:05:06.000Z',
created_by_account: '1',
discarded_at: null,
id: '1',
last_message: null,
latest_read_message_by_account: [],
latest_read_message_created_at: null,
message_expiration: 1209600,
unread: 0,
};
@ -41,7 +33,6 @@ const buildChatMessage = (id: string) => normalizeChatMessage({
account_id: '1',
content: `chat message #${id}`,
created_at: '2020-06-10T02:05:06.000Z',
emoji_reactions: null,
expiration: 1209600,
unread: true,
});
@ -58,53 +49,6 @@ describe('ChatKeys', () => {
expect(ChatKeys.chatMessages(id)).toEqual(['chats', 'messages', id]);
});
it('has a "chatSearch" key', () => {
const searchQuery = 'che';
expect(ChatKeys.chatSearch()).toEqual(['chats', 'search']);
expect(ChatKeys.chatSearch(searchQuery)).toEqual(['chats', 'search', searchQuery]);
});
});
describe('isLastMessage', () => {
describe('when its the last message', () => {
it('is truthy', () => {
const id = '5';
const newChat = { ...chat, last_message: { id } } as any;
const initialQueryData = {
pages: [
{ result: [newChat], hasMore: false, link: undefined },
],
pageParams: [undefined],
};
const initialFlattenedData = flattenPages(initialQueryData);
expect(sumBy(initialFlattenedData, (chat: IChat) => chat.unread)).toBe(0);
queryClient.setQueryData(ChatKeys.chatSearch(), initialQueryData);
expect(isLastMessage(id)).toBeTruthy();
});
});
describe('when its not the last message', () => {
it('is not truthy', () => {
const id = '5';
const newChat = { ...chat, last_message: { id } } as any;
const initialQueryData = {
pages: [
{ result: [newChat], hasMore: false, link: undefined },
],
pageParams: [undefined],
};
const initialFlattenedData = flattenPages(initialQueryData);
expect(sumBy(initialFlattenedData, (chat: IChat) => chat.unread)).toBe(0);
queryClient.setQueryData(ChatKeys.chatSearch(), initialQueryData);
expect(isLastMessage('10')).not.toBeTruthy();
});
});
});
describe('useChatMessages', () => {
@ -298,7 +242,7 @@ describe('useChatActions', () => {
const initialFlattenedData = flattenPages(initialQueryData);
expect(sumBy(initialFlattenedData, (chat: IChat) => chat.unread)).toBe(0);
queryClient.setQueryData(ChatKeys.chatSearch(), initialQueryData);
queryClient.setQueryData(['chats', 'search'], initialQueryData);
const { result } = renderHook(() => useChatActions(chat.id).markChatAsRead('2'));
@ -306,7 +250,7 @@ describe('useChatActions', () => {
expect(result.current).resolves.toBeDefined();
});
const nextQueryData = queryClient.getQueryData(ChatKeys.chatSearch());
const nextQueryData = queryClient.getQueryData(['chats', 'search']);
const nextFlattenedData = flattenPages(nextQueryData as any);
expect(sumBy(nextFlattenedData as any, (chat: IChat) => chat.unread)).toBe(nextUnreadCount);
});
@ -348,87 +292,4 @@ describe('useChatActions', () => {
expect(result.current.data.data).toEqual({ hello: 'world' });
});
});
describe('updateChat()', () => {
const nextUnreadCount = 5;
beforeEach(() => {
__stub((mock) => {
mock
.onPatch(`/api/v1/pleroma/chats/${chat.id}`)
.reply(200, { ...chat, unread: nextUnreadCount });
});
});
it('updates the queryCache for the chat', async() => {
const initialQueryData = { ...chat };
expect(initialQueryData.message_expiration).toBe(1209600);
queryClient.setQueryData(ChatKeys.chat(chat.id), initialQueryData);
const { result } = renderHook(() => {
const { updateChat } = useChatActions(chat.id);
useEffect(() => {
updateChat.mutate({ message_expiration: 1200 });
}, []);
return updateChat;
});
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
const nextQueryData = queryClient.getQueryData(ChatKeys.chat(chat.id));
expect((nextQueryData as any).message_expiration).toBe(1200);
});
});
describe('createReaction()', () => {
const chatMessage = buildChatMessage('1');
beforeEach(() => {
__stub((mock) => {
mock
.onPost(`/api/v1/pleroma/chats/${chat.id}/messages/${chatMessage.id}/reactions`)
.reply(200, { ...chatMessage.toJS(), emoji_reactions: [{ name: '👍', count: 1, me: true }] });
});
});
it('successfully updates the Chat Message record', async () => {
const initialQueryData = {
pages: [
{ result: [chatMessage], hasMore: false, link: undefined },
],
pageParams: [undefined],
};
queryClient.setQueryData(ChatKeys.chatMessages(chat.id), initialQueryData);
const { result } = renderHook(() => {
const { createReaction } = useChatActions(chat.id);
useEffect(() => {
createReaction.mutate({
messageId: chatMessage.id,
emoji: '👍',
chatMessage,
});
}, []);
return createReaction;
});
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
const updatedChatMessage = (queryClient.getQueryData(ChatKeys.chatMessages(chat.id)) as any).pages[0].result[0] as ChatMessage;
expect(updatedChatMessage.emoji_reactions).toEqual([{
name: '👍',
count: 1,
me: true,
}]);
});
});
});

View File

@ -7,9 +7,8 @@ import { ChatWidgetScreens, useChatContext } from 'soapbox/contexts/chat-context
import { useStatContext } from 'soapbox/contexts/stat-context';
import { useApi, useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
import { normalizeChatMessage } from 'soapbox/normalizers';
import toast from 'soapbox/toast';
import { ChatMessage } from 'soapbox/types/entities';
import { reOrderChatListItems, updateChatMessage } from 'soapbox/utils/chats';
import { reOrderChatListItems } from 'soapbox/utils/chats';
import { flattenPages, PaginatedResult, updatePageItem } from 'soapbox/utils/queries';
import { queryClient } from './client';
@ -17,64 +16,24 @@ import { useFetchRelationships } from './relationships';
import type { Account } from 'soapbox/schemas';
export const messageExpirationOptions = [604800, 1209600, 2592000, 7776000];
export enum MessageExpirationValues {
'SEVEN' = messageExpirationOptions[0],
'FOURTEEN' = messageExpirationOptions[1],
'THIRTY' = messageExpirationOptions[2],
'NINETY' = messageExpirationOptions[3]
}
export interface IChat {
accepted: boolean;
account: Account;
chat_type: 'channel' | 'direct';
created_at: string;
created_by_account: string;
discarded_at: null | string;
id: string;
last_message: null | {
account_id: string;
chat_id: string;
content: string;
created_at: string;
discarded_at: string | null;
id: string;
unread: boolean;
};
latest_read_message_by_account?: {
id: string;
date: string;
}[];
latest_read_message_created_at: null | string;
message_expiration?: MessageExpirationValues;
unread: number;
}
type UpdateChatVariables = {
message_expiration: MessageExpirationValues;
}
type CreateReactionVariables = {
messageId: string;
emoji: string;
chatMessage?: ChatMessage;
}
const ChatKeys = {
chat: (chatId?: string) => ['chats', 'chat', chatId] as const,
chatMessages: (chatId: string) => ['chats', 'messages', chatId] as const,
chatSearch: (searchQuery?: string) => searchQuery ? ['chats', 'search', searchQuery] : ['chats', 'search'] as const,
};
/** Check if item is most recent */
const isLastMessage = (chatMessageId: string): boolean => {
const queryData = queryClient.getQueryData<InfiniteData<PaginatedResult<IChat>>>(ChatKeys.chatSearch());
const items = flattenPages<IChat>(queryData);
const chat = items?.find((item) => item.last_message?.id === chatMessageId);
return !!chat;
};
const useChatMessages = (chat: IChat) => {
@ -122,7 +81,7 @@ const useChatMessages = (chat: IChat) => {
};
};
const useChats = (search?: string) => {
const useChats = () => {
const api = useApi();
const dispatch = useAppDispatch();
const features = useFeatures();
@ -133,11 +92,7 @@ const useChats = (search?: string) => {
const endpoint = features.chatsV2 ? '/api/v2/pleroma/chats' : '/api/v1/pleroma/chats';
const nextPageLink = pageParam?.link;
const uri = nextPageLink || endpoint;
const response = await api.get<IChat[]>(uri, {
params: search ? {
search,
} : undefined,
});
const response = await api.get<IChat[]>(uri);
const { data } = response;
const link = getNextLink(response);
@ -157,7 +112,7 @@ const useChats = (search?: string) => {
};
const queryInfo = useInfiniteQuery({
queryKey: ChatKeys.chatSearch(search),
queryKey: ['chats', 'search'],
queryFn: ({ pageParam }) => getChats(pageParam),
placeholderData: keepPreviousData,
enabled: features.chats,
@ -219,8 +174,8 @@ const useChatActions = (chatId: string) => {
const markChatAsRead = async (lastReadId: string) => {
return api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/read`, { last_read_id: lastReadId })
.then(({ data }) => {
updatePageItem(ChatKeys.chatSearch(), data, (o, n) => o.id === n.id);
const queryData = queryClient.getQueryData<InfiniteData<PaginatedResult<unknown>>>(ChatKeys.chatSearch());
updatePageItem(['chats', 'search'], data, (o, n) => o.id === n.id);
const queryData = queryClient.getQueryData<InfiniteData<PaginatedResult<unknown>>>(['chats', 'search']);
if (queryData) {
const flattenedQueryData: any = flattenPages(queryData)?.map((chat: any) => {
@ -293,7 +248,7 @@ const useChatActions = (chatId: string) => {
},
onSuccess: (response: any, variables, context) => {
const nextChat = { ...chat, last_message: response.data };
updatePageItem(ChatKeys.chatSearch(), nextChat, (o, n) => o.id === n.id);
updatePageItem(['chats', 'search'], nextChat, (o, n) => o.id === n.id);
updatePageItem(
ChatKeys.chatMessages(variables.chatId),
normalizeChatMessage(response.data),
@ -302,86 +257,23 @@ const useChatActions = (chatId: string) => {
reOrderChatListItems();
},
});
const updateChat = useMutation({
mutationFn: (data: UpdateChatVariables) => api.patch<IChat>(`/api/v1/pleroma/chats/${chatId}`, data),
onMutate: async (data) => {
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
await queryClient.cancelQueries({
queryKey: ChatKeys.chat(chatId),
});
// Snapshot the previous value
const prevChat = { ...chat };
const nextChat = { ...chat, ...data };
// Optimistically update to the new value
queryClient.setQueryData(ChatKeys.chat(chatId), nextChat);
// Return a context object with the snapshotted value
return { prevChat };
},
// If the mutation fails, use the context returned from onMutate to roll back
onError: (_error: any, _newData: any, context: any) => {
changeScreen(ChatWidgetScreens.CHAT, context.prevChat.id);
queryClient.setQueryData(ChatKeys.chat(chatId), context.prevChat);
toast.error('Chat Settings failed to update.');
},
onSuccess() {
queryClient.invalidateQueries({ queryKey: ChatKeys.chat(chatId) });
queryClient.invalidateQueries({ queryKey: ChatKeys.chatSearch() });
toast.success('Chat Settings updated successfully');
},
});
const deleteChatMessage = (chatMessageId: string) => api.delete<IChat>(`/api/v1/pleroma/chats/${chatId}/messages/${chatMessageId}`);
const acceptChat = useMutation({
mutationFn: () => api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/accept`),
onSuccess(response) {
changeScreen(ChatWidgetScreens.CHAT, response.data.id);
queryClient.invalidateQueries({ queryKey: ChatKeys.chat(chatId) });
queryClient.invalidateQueries({ queryKey: ChatKeys.chatMessages(chatId) });
queryClient.invalidateQueries({ queryKey: ChatKeys.chatSearch() });
},
});
const deleteChat = useMutation({
mutationFn: () => api.delete<IChat>(`/api/v1/pleroma/chats/${chatId}`),
onSuccess() {
changeScreen(ChatWidgetScreens.INBOX);
queryClient.invalidateQueries({ queryKey: ChatKeys.chatMessages(chatId) });
queryClient.invalidateQueries({ queryKey: ChatKeys.chatSearch() });
},
});
const createReaction = useMutation({
mutationFn: (data: CreateReactionVariables) => api.post(`/api/v1/pleroma/chats/${chatId}/messages/${data.messageId}/reactions`, {
emoji: data.emoji,
}),
// TODO: add optimistic updates
onSuccess(response) {
updateChatMessage(response.data);
},
});
const deleteReaction = useMutation({
mutationFn: (data: CreateReactionVariables) => api.delete(`/api/v1/pleroma/chats/${chatId}/messages/${data.messageId}/reactions/${data.emoji}`),
onSuccess() {
queryClient.invalidateQueries({ queryKey: ChatKeys.chatMessages(chatId) });
queryClient.invalidateQueries({ queryKey: ['chats', 'search'] });
},
});
return {
acceptChat,
createChatMessage,
createReaction,
deleteChat,
deleteChatMessage,
deleteReaction,
markChatAsRead,
updateChat,
};
};
export { ChatKeys, useChat, useChatActions, useChats, useChatMessages, isLastMessage };
export { ChatKeys, useChat, useChatActions, useChats, useChatMessages };