add names to conversation view and set header styles
Change-Id: Ic34b2cea754a5a82224a9fbf158b0126c7e44a5e
diff --git a/client/src/components/ConversationView.tsx b/client/src/components/ConversationView.tsx
index 0a8e22d..a6c0d35 100644
--- a/client/src/components/ConversationView.tsx
+++ b/client/src/components/ConversationView.tsx
@@ -15,13 +15,16 @@
* License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
-import { Box, Stack, Typography } from '@mui/material';
-import { Conversation, Message } from 'jami-web-common';
-import { useCallback, useContext, useEffect, useState } from 'react';
+import { Divider, Stack, Typography } from '@mui/material';
+import { Account, Conversation, ConversationMember, Message } from 'jami-web-common';
+import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
import { SocketContext } from '../contexts/Socket';
+import { useAccountQuery } from '../services/Account';
import { useConversationQuery, useMessagesQuery, useSendMessageMutation } from '../services/Conversation';
-import ConversationAvatar from './ConversationAvatar';
+import { translateEnumeration, TranslateEnumerationOptions } from '../utils/translations';
+import { AddParticipantButton, ShowOptionsMenuButton, StartAudioCallButton, StartVideoCallButton } from './Button';
import LoadingPage from './Loading';
import MessageList from './MessageList';
import SendMessageForm from './SendMessageForm';
@@ -30,18 +33,26 @@
accountId: string;
conversationId: string;
};
-const ConversationView = ({ accountId, conversationId, ...props }: ConversationViewProps) => {
+const ConversationView = ({ accountId, conversationId }: ConversationViewProps) => {
const socket = useContext(SocketContext);
+ const [account, setAccount] = useState<Account | undefined>();
const [conversation, setConversation] = useState<Conversation | undefined>();
const [messages, setMessages] = useState<Message[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(false);
+ const accountQuery = useAccountQuery(accountId);
const conversationQuery = useConversationQuery(accountId, conversationId);
const messagesQuery = useMessagesQuery(accountId, conversationId);
const sendMessageMutation = useSendMessageMutation(accountId, conversationId);
useEffect(() => {
+ if (accountQuery.isSuccess) {
+ setAccount(Account.from(accountQuery.data));
+ }
+ }, [accountQuery.isSuccess, accountQuery.data]);
+
+ useEffect(() => {
if (conversationQuery.isSuccess) {
const conversation = Conversation.from(accountId, conversationQuery.data);
setConversation(conversation);
@@ -56,12 +67,12 @@
}, [messagesQuery.isSuccess, messagesQuery.data]);
useEffect(() => {
- setIsLoading(conversationQuery.isLoading || messagesQuery.isLoading);
- }, [conversationQuery.isLoading, messagesQuery.isLoading]);
+ setIsLoading(accountQuery.isLoading || conversationQuery.isLoading || messagesQuery.isLoading);
+ }, [accountQuery.isLoading, conversationQuery.isLoading, messagesQuery.isLoading]);
useEffect(() => {
- setError(conversationQuery.isError || messagesQuery.isError);
- }, [conversationQuery.isError, messagesQuery.isError]);
+ setError(accountQuery.isLoading || conversationQuery.isError || messagesQuery.isError);
+ }, [accountQuery.isLoading, conversationQuery.isError, messagesQuery.isError]);
const sendMessage = useCallback((message: string) => sendMessageMutation.mutate(message), [sendMessageMutation]);
@@ -83,35 +94,94 @@
if (isLoading) {
return <LoadingPage />;
- } else if (error) {
+ } else if (error || !account || !conversation) {
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 height="100%">
+ <Stack padding="16px">
+ <ConversationHeader
+ account={account}
+ members={conversation.getMembers()}
+ adminTitle={conversation.infos.title as string}
+ />
</Stack>
- <Stack flexGrow={1} overflow="auto" direction="column-reverse">
- <MessageList messages={messages} />
+ <Divider
+ sx={{
+ borderTop: '1px solid #E5E5E5',
+ }}
+ />
+ <Stack flex={1} overflow="auto" direction="column-reverse" padding="0px 16px">
+ <MessageList account={account} members={conversation.getMembers()} messages={messages} />
</Stack>
- <Stack flexGrow={0}>
- <SendMessageForm onSend={sendMessage} />
+ <Divider
+ sx={{
+ margin: '30px 16px 0px 16px',
+ borderTop: '1px solid #E5E5E5',
+ }}
+ />
+ <Stack padding="16px">
+ <SendMessageForm account={account} members={conversation.getMembers()} onSend={sendMessage} />
</Stack>
</Stack>
);
};
+type ConversationHeaderProps = {
+ account: Account;
+ members: ConversationMember[];
+ adminTitle: string | undefined;
+};
+
+const ConversationHeader = ({ account, members, adminTitle }: ConversationHeaderProps) => {
+ const { t } = useTranslation();
+
+ const title = useMemo(() => {
+ if (adminTitle) {
+ return adminTitle;
+ }
+
+ const options: TranslateEnumerationOptions<ConversationMember> = {
+ elementPartialKey: 'member',
+ getElementValue: (member) => getMemberName(member),
+ translaters: [
+ () =>
+ // The user is chatting with themself
+ t('conversation_title_one', { member0: account?.getDisplayName() }),
+ (interpolations) => t('conversation_title_one', interpolations),
+ (interpolations) => t('conversation_title_two', interpolations),
+ (interpolations) => t('conversation_title_three', interpolations),
+ (interpolations) => t('conversation_title_four', interpolations),
+ (interpolations) => t('conversation_title_more', interpolations),
+ ],
+ };
+
+ return translateEnumeration<ConversationMember>(members, options);
+ }, [account, members, adminTitle, t]);
+
+ return (
+ <Stack direction="row">
+ <Stack flex={1} justifyContent="center" whiteSpace="nowrap" overflow="hidden">
+ <Typography variant="h3" textOverflow="ellipsis">
+ {title}
+ </Typography>
+ </Stack>
+ <Stack direction="row" spacing="20px">
+ <StartAudioCallButton />
+ <StartVideoCallButton />
+ <AddParticipantButton />
+ <ShowOptionsMenuButton />
+ </Stack>
+ </Stack>
+ );
+};
+
+const getMemberName = (member: ConversationMember) => {
+ const contact = member.contact;
+ return contact.getDisplayName();
+};
+
const addMessage = (sortedMessages: Message[], message: Message) => {
if (sortedMessages.length === 0) {
return [message];