blob: 16f67107a7436092b714648c5d51481a9006b7b3 [file] [log] [blame]
simon07b4eb02022-09-29 17:50:26 -04001import { Box, Stack, Typography } from '@mui/material';
simond47ef9e2022-09-28 22:24:28 -04002import { useCallback, useContext, useEffect, useState } from 'react';
simon07b4eb02022-09-29 17:50:26 -04003
simon35378692022-10-02 23:25:57 -04004import Conversation, { Message } from '../../../model/Conversation';
5import { SocketContext } from '../contexts/Socket';
6import { useConversationQuery, useMessagesQuery, useSendMessageMutation } from '../services/Conversation';
simon07b4eb02022-09-29 17:50:26 -04007import ConversationAvatar from './ConversationAvatar';
simon6b9ddfb2022-10-03 00:04:50 -04008import LoadingPage from './Loading';
Adrien Béraud35e7d7c2021-04-13 03:28:39 -04009import MessageList from './MessageList';
10import SendMessageForm from './SendMessageForm';
Adrien Béraud35e7d7c2021-04-13 03:28:39 -040011
simon35378692022-10-02 23:25:57 -040012type ConversationViewProps = {
13 accountId: string;
14 conversationId: string;
15};
16const ConversationView = ({ accountId, conversationId, ...props }: ConversationViewProps) => {
simond47ef9e2022-09-28 22:24:28 -040017 const socket = useContext(SocketContext);
simon35378692022-10-02 23:25:57 -040018 const [conversation, setConversation] = useState<Conversation | undefined>();
19 const [messages, setMessages] = useState<Message[]>([]);
simond47ef9e2022-09-28 22:24:28 -040020 const [isLoading, setIsLoading] = useState(true);
21 const [error, setError] = useState(false);
idillon08f77172022-09-13 19:14:17 -040022
simon80b7b3b2022-09-28 17:50:10 -040023 const conversationQuery = useConversationQuery(accountId, conversationId);
24 const messagesQuery = useMessagesQuery(accountId, conversationId);
25 const sendMessageMutation = useSendMessageMutation(accountId, conversationId);
Adrien Béraud35e7d7c2021-04-13 03:28:39 -040026
Adrien Béraud5e9e19b2021-04-22 01:38:53 -040027 useEffect(() => {
idillonea465602022-09-13 19:58:51 -040028 if (conversationQuery.isSuccess) {
simon80b7b3b2022-09-28 17:50:10 -040029 const conversation = Conversation.from(accountId, conversationQuery.data);
simond47ef9e2022-09-28 22:24:28 -040030 setConversation(conversation);
idillon08f77172022-09-13 19:14:17 -040031 }
simon80b7b3b2022-09-28 17:50:10 -040032 }, [accountId, conversationQuery.isSuccess, conversationQuery.data]);
idillon08f77172022-09-13 19:14:17 -040033
34 useEffect(() => {
idillonea465602022-09-13 19:58:51 -040035 if (messagesQuery.isSuccess) {
simond47ef9e2022-09-28 22:24:28 -040036 const sortedMessages = sortMessages(messagesQuery.data);
37 setMessages(sortedMessages);
idillon08f77172022-09-13 19:14:17 -040038 }
simon80b7b3b2022-09-28 17:50:10 -040039 }, [messagesQuery.isSuccess, messagesQuery.data]);
idillon08f77172022-09-13 19:14:17 -040040
41 useEffect(() => {
simond47ef9e2022-09-28 22:24:28 -040042 setIsLoading(conversationQuery.isLoading || messagesQuery.isLoading);
43 }, [conversationQuery.isLoading, messagesQuery.isLoading]);
idillonea465602022-09-13 19:58:51 -040044
Adrien Béraudabba2e52021-04-24 21:39:56 -040045 useEffect(() => {
simond47ef9e2022-09-28 22:24:28 -040046 setError(conversationQuery.isError || messagesQuery.isError);
47 }, [conversationQuery.isError, messagesQuery.isError]);
48
simon35378692022-10-02 23:25:57 -040049 const sendMessage = useCallback((message: string) => sendMessageMutation.mutate(message), [sendMessageMutation]);
simond47ef9e2022-09-28 22:24:28 -040050
51 useEffect(() => {
52 if (!conversation) return;
simon80b7b3b2022-09-28 17:50:10 -040053 console.log(`io set conversation ${conversationId} ` + socket);
simon35378692022-10-02 23:25:57 -040054 if (socket) {
55 socket.emit('conversation', {
56 accountId,
57 conversationId,
58 });
59 socket.off('newMessage');
60 socket.on('newMessage', (data) => {
61 console.log('newMessage');
62 setMessages((messages) => addMessage(messages, data));
63 });
64 }
simon80b7b3b2022-09-28 17:50:10 -040065 }, [accountId, conversation, conversationId, socket]);
Adrien Béraudabba2e52021-04-24 21:39:56 -040066
idillonea465602022-09-13 19:58:51 -040067 if (isLoading) {
simond47ef9e2022-09-28 22:24:28 -040068 return <LoadingPage />;
idillon08f77172022-09-13 19:14:17 -040069 } else if (error) {
simon80b7b3b2022-09-28 17:50:10 -040070 return <div>Error loading {conversationId}</div>;
Adrien Béraud5e9e19b2021-04-22 01:38:53 -040071 }
idillonbef18a52022-09-01 01:51:40 -040072
73 return (
simond47ef9e2022-09-28 22:24:28 -040074 <Stack flexGrow={1} height="100%">
idillonbef18a52022-09-01 01:51:40 -040075 <Stack direction="row" flexGrow={0}>
76 <Box style={{ margin: 16, flexShrink: 0 }}>
idillon08f77172022-09-13 19:14:17 -040077 <ConversationAvatar displayName={conversation?.getDisplayNameNoFallback()} />
idillonbef18a52022-09-01 01:51:40 -040078 </Box>
simond47ef9e2022-09-28 22:24:28 -040079 <Box style={{ flex: '1 1 auto', overflow: 'hidden' }}>
80 <Typography className="title" variant="h6">
81 {conversation?.getDisplayName()}
82 </Typography>
83 <Typography className="subtitle" variant="subtitle1">
simon80b7b3b2022-09-28 17:50:10 -040084 {conversationId}
simond47ef9e2022-09-28 22:24:28 -040085 </Typography>
idillonbef18a52022-09-01 01:51:40 -040086 </Box>
87 </Stack>
idillonaedab942022-09-01 14:29:43 -040088 <Stack flexGrow={1} overflow="auto" direction="column-reverse">
simond47ef9e2022-09-28 22:24:28 -040089 <MessageList messages={messages} />
idillonbef18a52022-09-01 01:51:40 -040090 </Stack>
91 <Stack flexGrow={0}>
92 <SendMessageForm onSend={sendMessage} />
93 </Stack>
94 </Stack>
simond47ef9e2022-09-28 22:24:28 -040095 );
96};
Adrien Béraud35e7d7c2021-04-13 03:28:39 -040097
simon35378692022-10-02 23:25:57 -040098const addMessage = (sortedMessages: Message[], message: Message) => {
idillon08f77172022-09-13 19:14:17 -040099 if (sortedMessages.length === 0) {
simond47ef9e2022-09-28 22:24:28 -0400100 return [message];
idillon08f77172022-09-13 19:14:17 -0400101 } else if (message.id === sortedMessages[sortedMessages.length - 1].linearizedParent) {
simond47ef9e2022-09-28 22:24:28 -0400102 return [...sortedMessages, message];
idillon08f77172022-09-13 19:14:17 -0400103 } else if (message.linearizedParent === sortedMessages[0].id) {
simond47ef9e2022-09-28 22:24:28 -0400104 return [message, ...sortedMessages];
idillon08f77172022-09-13 19:14:17 -0400105 } else {
simond47ef9e2022-09-28 22:24:28 -0400106 console.log("Can't insert message " + message.id);
simon35378692022-10-02 23:25:57 -0400107 return sortedMessages;
idillon08f77172022-09-13 19:14:17 -0400108 }
simond47ef9e2022-09-28 22:24:28 -0400109};
idillon08f77172022-09-13 19:14:17 -0400110
simon35378692022-10-02 23:25:57 -0400111const sortMessages = (messages: Message[]) => {
112 let sortedMessages: Message[] = [];
simond47ef9e2022-09-28 22:24:28 -0400113 messages.forEach((message) => (sortedMessages = addMessage(sortedMessages, message)));
114 return sortedMessages;
115};
idillon08f77172022-09-13 19:14:17 -0400116
simond47ef9e2022-09-28 22:24:28 -0400117export default ConversationView;