Add toggleable chat drawer in call
During a call, the chat button is enabled and lets the user open the
chat drawer.
GitLab: #177
Change-Id: I7a2ae09fca5af904c3280bc948a2d36135c1c63d
diff --git a/client/src/components/CallButtons.tsx b/client/src/components/CallButtons.tsx
index 7ccdd91..b127a77 100644
--- a/client/src/components/CallButtons.tsx
+++ b/client/src/components/CallButtons.tsx
@@ -84,7 +84,17 @@
});
export const CallingChatButton = (props: ExpandableButtonProps) => {
- return <CallButton aria-label="chat" Icon={ChatBubbleIcon} {...props} />;
+ const { setIsChatShown } = useContext(CallContext);
+ return (
+ <CallButton
+ aria-label="chat"
+ Icon={ChatBubbleIcon}
+ onClick={() => {
+ setIsChatShown((v) => !v);
+ }}
+ {...props}
+ />
+ );
};
export const CallingEndButton = (props: ExpandableButtonProps) => {
diff --git a/client/src/components/CallChatDrawer.tsx b/client/src/components/CallChatDrawer.tsx
new file mode 100644
index 0000000..d2040d7
--- /dev/null
+++ b/client/src/components/CallChatDrawer.tsx
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+import { Divider, Stack, Typography } from '@mui/material';
+import { useContext } from 'react';
+
+import { CallContext } from '../contexts/CallProvider';
+import { ConversationContext } from '../contexts/ConversationProvider';
+import ChatInterface from '../pages/ChatInterface';
+import { CloseButton } from './Button';
+
+export default () => {
+ return (
+ <Stack
+ width="33%"
+ height="100%"
+ sx={{
+ backgroundColor: 'white',
+ }}
+ >
+ <CallChatDrawerHeader />
+ <Divider
+ sx={{
+ borderTop: '1px solid #E5E5E5',
+ }}
+ />
+ <ChatInterface />
+ </Stack>
+ );
+};
+
+const CallChatDrawerHeader = () => {
+ const { setIsChatShown } = useContext(CallContext);
+ const { conversation } = useContext(ConversationContext);
+
+ // TODO: Improve this to support multiple members
+ const contact = conversation.getFirstMember().contact;
+
+ return (
+ <Stack direction="row" padding={2} spacing={2} alignItems="center">
+ <CloseButton
+ onClick={() => {
+ setIsChatShown(false);
+ }}
+ />
+ <Stack direction="column">
+ <Typography variant="h3" textOverflow="ellipsis">
+ {contact.getDisplayName()}
+ </Typography>
+ </Stack>
+ </Stack>
+ );
+};
diff --git a/client/src/components/ConversationView.tsx b/client/src/components/ConversationView.tsx
index 52215e8..064efcf 100644
--- a/client/src/components/ConversationView.tsx
+++ b/client/src/components/ConversationView.tsx
@@ -16,7 +16,7 @@
* <https://www.gnu.org/licenses/>.
*/
import { Divider, Stack, Typography } from '@mui/material';
-import { Account, ConversationMember } from 'jami-web-common';
+import { ConversationMember } from 'jami-web-common';
import { useContext, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -28,38 +28,28 @@
import { AddParticipantButton, ShowOptionsMenuButton, StartAudioCallButton, StartVideoCallButton } from './Button';
const ConversationView = () => {
- const { account } = useAuthContext();
- const { conversationId, conversation } = useContext(ConversationContext);
-
return (
<Stack flexGrow={1} height="100%">
- <ConversationHeader
- account={account}
- members={conversation.getMembers()}
- adminTitle={conversation.infos.title as string}
- conversationId={conversationId}
- />
+ <ConversationHeader />
<Divider
sx={{
borderTop: '1px solid #E5E5E5',
}}
/>
- <ChatInterface conversationId={conversationId} members={conversation.getMembers()} />
+ <ChatInterface />
</Stack>
);
};
-type ConversationHeaderProps = {
- account: Account;
- conversationId: string;
- members: ConversationMember[];
- adminTitle: string | undefined;
-};
-
-const ConversationHeader = ({ account, members, adminTitle }: ConversationHeaderProps) => {
+const ConversationHeader = () => {
+ const { account } = useAuthContext();
+ const { conversation } = useContext(ConversationContext);
const { t } = useTranslation();
const { conversationId } = useContext(ConversationContext);
+ const members = conversation.getMembers();
+ const adminTitle = conversation.infos.title as string;
+
const title = useMemo(() => {
if (adminTitle) {
return adminTitle;
diff --git a/client/src/contexts/CallProvider.tsx b/client/src/contexts/CallProvider.tsx
index de2a6d7..5595000 100644
--- a/client/src/contexts/CallProvider.tsx
+++ b/client/src/contexts/CallProvider.tsx
@@ -21,7 +21,7 @@
import { useUrlParams } from '../hooks/useUrlParams';
import { CallRouteParams } from '../router';
-import { WithChildren } from '../utils/utils';
+import { SetState, WithChildren } from '../utils/utils';
import { ConversationContext } from './ConversationProvider';
import { WebRtcContext } from './WebRtcProvider';
import { WebSocketContext } from './WebSocketProvider';
@@ -45,6 +45,8 @@
setAudioStatus: (isOn: boolean) => void;
isVideoOn: boolean;
setVideoStatus: (isOn: boolean) => void;
+ isChatShown: boolean;
+ setIsChatShown: SetState<boolean>;
callRole: CallRole;
callStatus: CallStatus;
@@ -65,6 +67,8 @@
setAudioStatus: () => {},
isVideoOn: false,
setVideoStatus: () => {},
+ isChatShown: false,
+ setIsChatShown: () => {},
callRole: 'caller',
callStatus: CallStatus.Default,
@@ -89,6 +93,7 @@
const [isAudioOn, setIsAudioOn] = useState(false);
const [isVideoOn, setIsVideoOn] = useState(false);
+ const [isChatShown, setIsChatShown] = useState(false);
const [callStatus, setCallStatus] = useState(routeState?.callStatus);
// TODO: This logic will have to change to support multiple people in a call. Could we move this logic to the server?
@@ -256,6 +261,8 @@
setAudioStatus,
isVideoOn,
setVideoStatus,
+ isChatShown,
+ setIsChatShown,
callRole,
callStatus,
acceptCall,
diff --git a/client/src/pages/CallInterface.tsx b/client/src/pages/CallInterface.tsx
index b6266ac..29dd4e0 100644
--- a/client/src/pages/CallInterface.tsx
+++ b/client/src/pages/CallInterface.tsx
@@ -44,11 +44,12 @@
CallingVideoCameraButton,
CallingVolumeButton,
} from '../components/CallButtons';
+import CallChatDrawer from '../components/CallChatDrawer';
import { CallContext, CallStatus } from '../contexts/CallProvider';
import { CallPending } from './CallPending';
export default () => {
- const { callRole, callStatus } = useContext(CallContext);
+ const { callRole, callStatus, isChatShown } = useContext(CallContext);
if (callStatus !== CallStatus.InCall) {
return (
@@ -60,7 +61,12 @@
);
}
- return <CallInterface />;
+ return (
+ <Box flexGrow={1} display="flex">
+ <CallInterface />
+ {isChatShown && <CallChatDrawer />}
+ </Box>
+ );
};
interface Props {
@@ -86,7 +92,7 @@
}, [remoteStream]);
return (
- <>
+ <Box display="flex" flexGrow={1}>
<video
ref={remoteVideoRef}
autoPlay
@@ -123,7 +129,7 @@
</Grid>
</Grid>
</Box>
- </>
+ </Box>
);
};
diff --git a/client/src/pages/ChatInterface.tsx b/client/src/pages/ChatInterface.tsx
index f30c15a..5bcd8a2 100644
--- a/client/src/pages/ChatInterface.tsx
+++ b/client/src/pages/ChatInterface.tsx
@@ -16,7 +16,7 @@
* <https://www.gnu.org/licenses/>.
*/
import { Box, Divider, Stack } from '@mui/material';
-import { ConversationMember, ConversationMessage, Message, WebSocketMessageType } from 'jami-web-common';
+import { ConversationMessage, Message, WebSocketMessageType } from 'jami-web-common';
import { useCallback, useContext, useEffect, useState } from 'react';
import { useDropzone } from 'react-dropzone';
@@ -24,16 +24,14 @@
import LoadingPage from '../components/Loading';
import MessageList from '../components/MessageList';
import SendMessageForm from '../components/SendMessageForm';
+import { ConversationContext } from '../contexts/ConversationProvider';
import { WebSocketContext } from '../contexts/WebSocketProvider';
import { useMessagesQuery, useSendMessageMutation } from '../services/Conversation';
import { FileHandler } from '../utils/files';
-type ChatInterfaceProps = {
- conversationId: string;
- members: ConversationMember[];
-};
-const ChatInterface = ({ conversationId, members }: ChatInterfaceProps) => {
+const ChatInterface = () => {
const webSocket = useContext(WebSocketContext);
+ const { conversationId, conversation } = useContext(ConversationContext);
const [messages, setMessages] = useState<Message[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(false);
@@ -107,6 +105,8 @@
return <div>Error loading {conversationId}</div>;
}
+ const members = conversation.getMembers();
+
return (
<Stack flex={1} overflow="hidden" {...getRootProps()} paddingBottom="16px">
{isDragActive && (