Refactor 'createChatMessage' mutation
This commit is contained in:
parent
2460d85460
commit
e7106a35b3
|
@ -1,13 +1,10 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
import classNames from 'clsx';
|
||||
import React, { MutableRefObject, useEffect, useState } from 'react';
|
||||
|
||||
import { Stack } from 'soapbox/components/ui';
|
||||
// import UploadProgress from 'soapbox/components/upload-progress';
|
||||
// import UploadButton from 'soapbox/features/compose/components/upload_button';
|
||||
import { useOwnAccount } from 'soapbox/hooks';
|
||||
import { ChatKeys, IChat, useChatActions } from 'soapbox/queries/chats';
|
||||
import { queryClient } from 'soapbox/queries/client';
|
||||
import { IChat, useChatActions } from 'soapbox/queries/chats';
|
||||
// import { truncateFilename } from 'soapbox/utils/media';
|
||||
|
||||
import ChatComposer from './chat-composer';
|
||||
|
@ -26,8 +23,6 @@ interface ChatInterface {
|
|||
* Reused between floating desktop chats and fullscreen/mobile chats.
|
||||
*/
|
||||
const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
||||
const account = useOwnAccount();
|
||||
|
||||
const { createChatMessage, acceptChat } = useChatActions(chat.id);
|
||||
|
||||
const [content, setContent] = useState<string>('');
|
||||
|
@ -39,58 +34,20 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
|
||||
const isSubmitDisabled = content.length === 0 && !attachment;
|
||||
|
||||
const submitMessage = useMutation(({ chatId, content }: any) => createChatMessage(chatId, content), {
|
||||
retry: false,
|
||||
onMutate: async (newMessage: any) => {
|
||||
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
|
||||
await queryClient.cancelQueries(['chats', 'messages', chat.id]);
|
||||
|
||||
// Snapshot the previous value
|
||||
const prevChatMessages = queryClient.getQueryData(['chats', 'messages', chat.id]);
|
||||
const prevContent = content;
|
||||
|
||||
// Clear state (content, attachment, etc)
|
||||
clearState();
|
||||
|
||||
// Optimistically update to the new value
|
||||
queryClient.setQueryData(['chats', 'messages', chat.id], (prevResult: any) => {
|
||||
const newResult = { ...prevResult };
|
||||
newResult.pages = newResult.pages.map((page: any, idx: number) => {
|
||||
if (idx === 0) {
|
||||
return {
|
||||
...page,
|
||||
result: [...page.result, {
|
||||
...newMessage,
|
||||
id: String(Number(new Date())),
|
||||
created_at: new Date(),
|
||||
account_id: account?.id,
|
||||
pending: true,
|
||||
unread: true,
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
return page;
|
||||
});
|
||||
|
||||
return newResult;
|
||||
});
|
||||
|
||||
// Return a context object with the snapshotted value
|
||||
return { prevChatMessages, prevContent };
|
||||
},
|
||||
// If the mutation fails, use the context returned from onMutate to roll back
|
||||
onError: (_error: any, _newData: any, context: any) => {
|
||||
setContent(context.prevContent);
|
||||
queryClient.setQueryData(['chats', 'messages', chat.id], context.prevChatMessages);
|
||||
const submitMessage = () => {
|
||||
createChatMessage.mutate({ chatId: chat.id, content }, {
|
||||
onError: (_error, _variables, context: any) => {
|
||||
setContent(context.prevContent as string);
|
||||
setErrorSubmittingMessage(true);
|
||||
},
|
||||
onSuccess: () => {
|
||||
setErrorSubmittingMessage(false);
|
||||
queryClient.invalidateQueries(ChatKeys.chatMessages(chat.id));
|
||||
},
|
||||
});
|
||||
|
||||
clearState();
|
||||
};
|
||||
|
||||
const clearState = () => {
|
||||
setContent('');
|
||||
setAttachment(undefined);
|
||||
|
@ -101,8 +58,8 @@ const Chat: React.FC<ChatInterface> = ({ chat, inputRef, className }) => {
|
|||
};
|
||||
|
||||
const sendMessage = () => {
|
||||
if (!isSubmitDisabled && !submitMessage.isLoading) {
|
||||
submitMessage.mutate({ chatId: chat.id, content });
|
||||
if (!isSubmitDisabled && !createChatMessage.isLoading) {
|
||||
submitMessage();
|
||||
|
||||
if (!chat.accepted) {
|
||||
acceptChat.mutate();
|
||||
|
|
|
@ -295,6 +295,43 @@ describe('useChatActions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('createChatMessage()', () => {
|
||||
beforeEach(() => {
|
||||
const initialQueryData = {
|
||||
pages: [
|
||||
{ result: [buildChatMessage('1')], hasMore: false, link: undefined },
|
||||
],
|
||||
pageParams: [undefined],
|
||||
};
|
||||
|
||||
queryClient.setQueryData(ChatKeys.chatMessages(chat.id), initialQueryData);
|
||||
|
||||
__stub((mock) => {
|
||||
mock
|
||||
.onPost(`/api/v1/pleroma/chats/${chat.id}/messages`)
|
||||
.reply(200, { hello: 'world' });
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a chat message', async() => {
|
||||
const { result } = renderHook(() => {
|
||||
const { createChatMessage } = useChatActions(chat.id);
|
||||
|
||||
useEffect(() => {
|
||||
createChatMessage.mutate({ chatId: chat.id, content: 'hello' });
|
||||
}, []);
|
||||
|
||||
return createChatMessage;
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
expect(result.current.data.data).toEqual({ hello: 'world' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateChat()', () => {
|
||||
const nextUnreadCount = 5;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { getNextLink } from 'soapbox/api';
|
|||
import compareId from 'soapbox/compare_id';
|
||||
import { ChatWidgetScreens, useChatContext } from 'soapbox/contexts/chat-context';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
import { useApi, useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { useApi, useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||
import { normalizeChatMessage } from 'soapbox/normalizers';
|
||||
import { flattenPages, PaginatedResult, updatePageItem } from 'soapbox/utils/queries';
|
||||
|
||||
|
@ -202,8 +202,10 @@ const useChat = (chatId?: string) => {
|
|||
};
|
||||
|
||||
const useChatActions = (chatId: string) => {
|
||||
const account = useOwnAccount();
|
||||
const api = useApi();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { setUnreadChatsCount } = useStatContext();
|
||||
|
||||
const { chat, changeScreen } = useChatContext();
|
||||
|
@ -230,9 +232,55 @@ const useChatActions = (chatId: string) => {
|
|||
.catch(() => null);
|
||||
};
|
||||
|
||||
const createChatMessage = (chatId: string, content: string) => {
|
||||
return api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/messages`, { content });
|
||||
const createChatMessage = useMutation(
|
||||
(
|
||||
{ chatId, content }: { chatId: string, content: string },
|
||||
) => api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/messages`, { content }),
|
||||
{
|
||||
retry: false,
|
||||
onMutate: async (variables) => {
|
||||
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
|
||||
await queryClient.cancelQueries(['chats', 'messages', variables.chatId]);
|
||||
|
||||
// Snapshot the previous value
|
||||
const prevContent = variables.content;
|
||||
const prevChatMessages = queryClient.getQueryData(['chats', 'messages', variables.chatId]);
|
||||
|
||||
// Optimistically update to the new value
|
||||
queryClient.setQueryData(ChatKeys.chatMessages(variables.chatId), (prevResult: any) => {
|
||||
const newResult = { ...prevResult };
|
||||
newResult.pages = newResult.pages.map((page: any, idx: number) => {
|
||||
if (idx === 0) {
|
||||
return {
|
||||
...page,
|
||||
result: [...page.result, {
|
||||
content: variables.content,
|
||||
id: String(Number(new Date())),
|
||||
created_at: new Date(),
|
||||
account_id: account?.id,
|
||||
pending: true,
|
||||
unread: true,
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
return page;
|
||||
});
|
||||
|
||||
return newResult;
|
||||
});
|
||||
|
||||
return { prevChatMessages, prevContent };
|
||||
},
|
||||
// If the mutation fails, use the context returned from onMutate to roll back
|
||||
onError: (_error: any, variables, context: any) => {
|
||||
queryClient.setQueryData(['chats', 'messages', variables.chatId], context.prevChatMessages);
|
||||
},
|
||||
onSuccess: (_data: any, variables) => {
|
||||
queryClient.invalidateQueries(ChatKeys.chatMessages(variables.chatId));
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const updateChat = useMutation((data: UpdateChatVariables) => api.patch<IChat>(`/api/v1/pleroma/chats/${chatId}`, data), {
|
||||
onMutate: async (data) => {
|
||||
|
|
Loading…
Reference in New Issue