Convert files in themes/ services/ contexts/ to TS
Convert all Javascript files in `client/src/themes`, `client/src/service`, `client/src/contexts` to Typescript.
Convert SvgIcon, Input, ConversationView, Button components to Typescript
Gitlab #30
Change-Id: I0d0505c28e21c771906edf8d5e7b8ce36126fa64
diff --git a/client/src/components/ConversationView.tsx b/client/src/components/ConversationView.tsx
new file mode 100644
index 0000000..ac738b4
--- /dev/null
+++ b/client/src/components/ConversationView.tsx
@@ -0,0 +1,117 @@
+import { Box, Stack, Typography } from '@mui/material';
+import { useCallback, useContext, useEffect, useState } from 'react';
+
+import Conversation, { Message } from '../../../model/Conversation';
+import { SocketContext } from '../contexts/Socket';
+import { useConversationQuery, useMessagesQuery, useSendMessageMutation } from '../services/Conversation';
+import ConversationAvatar from './ConversationAvatar';
+import LoadingPage from './loading';
+import MessageList from './MessageList';
+import SendMessageForm from './SendMessageForm';
+
+type ConversationViewProps = {
+ accountId: string;
+ conversationId: string;
+};
+const ConversationView = ({ accountId, conversationId, ...props }: ConversationViewProps) => {
+ const socket = useContext(SocketContext);
+ const [conversation, setConversation] = useState<Conversation | undefined>();
+ const [messages, setMessages] = useState<Message[]>([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(false);
+
+ const conversationQuery = useConversationQuery(accountId, conversationId);
+ const messagesQuery = useMessagesQuery(accountId, conversationId);
+ const sendMessageMutation = useSendMessageMutation(accountId, conversationId);
+
+ useEffect(() => {
+ if (conversationQuery.isSuccess) {
+ const conversation = Conversation.from(accountId, conversationQuery.data);
+ setConversation(conversation);
+ }
+ }, [accountId, conversationQuery.isSuccess, conversationQuery.data]);
+
+ useEffect(() => {
+ if (messagesQuery.isSuccess) {
+ const sortedMessages = sortMessages(messagesQuery.data);
+ setMessages(sortedMessages);
+ }
+ }, [messagesQuery.isSuccess, messagesQuery.data]);
+
+ useEffect(() => {
+ setIsLoading(conversationQuery.isLoading || messagesQuery.isLoading);
+ }, [conversationQuery.isLoading, messagesQuery.isLoading]);
+
+ useEffect(() => {
+ setError(conversationQuery.isError || messagesQuery.isError);
+ }, [conversationQuery.isError, messagesQuery.isError]);
+
+ const sendMessage = useCallback((message: string) => sendMessageMutation.mutate(message), [sendMessageMutation]);
+
+ useEffect(() => {
+ if (!conversation) return;
+ console.log(`io set conversation ${conversationId} ` + socket);
+ if (socket) {
+ socket.emit('conversation', {
+ accountId,
+ conversationId,
+ });
+ socket.off('newMessage');
+ socket.on('newMessage', (data) => {
+ console.log('newMessage');
+ setMessages((messages) => addMessage(messages, data));
+ });
+ }
+ }, [accountId, conversation, conversationId, socket]);
+
+ if (isLoading) {
+ return <LoadingPage />;
+ } else if (error) {
+ return <div>Error loading {conversationId}</div>;
+ }
+
+ return (
+ <Stack flexGrow={1} height="100%">
+ <Stack direction="row" flexGrow={0}>
+ <Box style={{ margin: 16, flexShrink: 0 }}>
+ <ConversationAvatar displayName={conversation?.getDisplayNameNoFallback()} />
+ </Box>
+ <Box style={{ flex: '1 1 auto', overflow: 'hidden' }}>
+ <Typography className="title" variant="h6">
+ {conversation?.getDisplayName()}
+ </Typography>
+ <Typography className="subtitle" variant="subtitle1">
+ {conversationId}
+ </Typography>
+ </Box>
+ </Stack>
+ <Stack flexGrow={1} overflow="auto" direction="column-reverse">
+ <MessageList messages={messages} />
+ </Stack>
+ <Stack flexGrow={0}>
+ <SendMessageForm onSend={sendMessage} />
+ </Stack>
+ </Stack>
+ );
+};
+
+const addMessage = (sortedMessages: Message[], message: Message) => {
+ if (sortedMessages.length === 0) {
+ return [message];
+ } else if (message.id === sortedMessages[sortedMessages.length - 1].linearizedParent) {
+ return [...sortedMessages, message];
+ } else if (message.linearizedParent === sortedMessages[0].id) {
+ return [message, ...sortedMessages];
+ } else {
+ console.log("Can't insert message " + message.id);
+ return sortedMessages;
+ }
+};
+
+const sortMessages = (messages: Message[]) => {
+ let sortedMessages: Message[] = [];
+ messages.forEach((message) => (sortedMessages = addMessage(sortedMessages, message)));
+ return sortedMessages;
+};
+
+export default ConversationView;