diff --git a/.loki/reference/chrome_Components_Icons_all.png b/.loki/reference/chrome_Components_Icons_all.png
index 9ee15f4ff..3f27dfcbc 100644
Binary files a/.loki/reference/chrome_Components_Icons_all.png and b/.loki/reference/chrome_Components_Icons_all.png differ
diff --git a/.loki/reference/chrome_Components_Icons_phone.png b/.loki/reference/chrome_Components_Icons_phone.png
new file mode 100644
index 000000000..ea142fac6
Binary files /dev/null and b/.loki/reference/chrome_Components_Icons_phone.png differ
diff --git a/.loki/reference/chrome_Components_Icons_phoneOff.png b/.loki/reference/chrome_Components_Icons_phoneOff.png
new file mode 100644
index 000000000..d621a0f3a
Binary files /dev/null and b/.loki/reference/chrome_Components_Icons_phoneOff.png differ
diff --git a/.loki/reference/chrome_Components_Icons_video.png b/.loki/reference/chrome_Components_Icons_video.png
new file mode 100644
index 000000000..5c8c71d51
Binary files /dev/null and b/.loki/reference/chrome_Components_Icons_video.png differ
diff --git a/.loki/reference/chrome_Components_Icons_videoIcon.png b/.loki/reference/chrome_Components_Icons_videoIcon.png
new file mode 100644
index 000000000..5c8c71d51
Binary files /dev/null and b/.loki/reference/chrome_Components_Icons_videoIcon.png differ
diff --git a/package.json b/package.json
index eea0f8041..6db73a542 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,7 @@
},
"dependencies": {
"@kossnocorp/desvg": "^0.2.0",
- "@rocket.chat/sdk": "^1.0.0-alpha.41",
+ "@rocket.chat/sdk": "^1.0.0-alpha.42",
"@rocket.chat/ui-kit": "^0.14.1",
"css-vars-ponyfill": "^2.3.2",
"date-fns": "^2.15.0",
diff --git a/src/components/Calls/CallIFrame.js b/src/components/Calls/CallIFrame.js
new file mode 100644
index 000000000..cc943eb39
--- /dev/null
+++ b/src/components/Calls/CallIFrame.js
@@ -0,0 +1,32 @@
+import { h } from 'preact';
+
+import { Livechat } from '../../api';
+import store from '../../store';
+import { createClassName } from '../helpers';
+import { CallStatus } from './CallStatus';
+import styles from './styles.scss';
+
+
+export const CallIframe = () => {
+ const { token, room, incomingCallAlert, ongoingCall } = store.state;
+ const url = `${ Livechat.client.host }/meet/${ room._id }?token=${ token }&layout=embedded`;
+ window.handleIframeClose = () => store.setState({ incomingCallAlert: { ...incomingCallAlert, show: false } });
+ window.expandCall = () => {
+ window.open(
+ `${ Livechat.client.host }/meet/${ room._id }?token=${ token }`,
+ room._id,
+ );
+ return store.setState({
+ incomingCallAlert: { ...incomingCallAlert, show: false },
+ ongoingCall: {
+ ...ongoingCall,
+ callStatus: CallStatus.IN_PROGRESS_DIFFERENT_TAB,
+ },
+ });
+ };
+ return (
+
+
+
+ );
+};
diff --git a/src/components/Calls/CallNotification.js b/src/components/Calls/CallNotification.js
new file mode 100644
index 000000000..767824304
--- /dev/null
+++ b/src/components/Calls/CallNotification.js
@@ -0,0 +1,111 @@
+import { h } from 'preact';
+import { useState } from 'preact/compat';
+
+import { Livechat } from '../../api';
+import I18n from '../../i18n';
+import PhoneAccept from '../../icons/phone.svg';
+import PhoneDecline from '../../icons/phoneOff.svg';
+import constants from '../../lib/constants';
+import store from '../../store';
+import { Avatar } from '../Avatar';
+import { Button } from '../Button';
+import { createClassName, getAvatarUrl, isMobileDevice } from '../helpers';
+import { CallStatus } from './CallStatus';
+import styles from './styles.scss';
+
+
+export const CallNotification = ({
+ callProvider,
+ callerUsername,
+ url,
+ dispatch,
+ time,
+ rid,
+ callId,
+}) => {
+ const [show, setShow] = useState(true);
+
+ const callInNewTab = async () => {
+ const { token } = store.state;
+ const url = `${ Livechat.client.host }/meet/${ rid }?token=${ token }`;
+ await dispatch({
+ ongoingCall: {
+ callStatus: CallStatus.IN_PROGRESS_DIFFERENT_TAB,
+ time: { time },
+ },
+ incomingCallAlert: {
+ show: false,
+ callProvider,
+ },
+ });
+ window.open(url, rid);
+ };
+
+ const acceptClick = async () => {
+ setShow(!{ show });
+ switch (callProvider) {
+ case constants.jitsiCallStartedMessageType: {
+ window.open(url, rid);
+ await dispatch({
+ incomingCallAlert: { show: false, url, callProvider },
+ ongoingCall: {
+ callStatus: CallStatus.IN_PROGRESS_DIFFERENT_TAB,
+ time: { time },
+ },
+ });
+ break;
+ }
+ case constants.webRTCCallStartedMessageType: {
+ await Livechat.updateCallStatus(CallStatus.IN_PROGRESS, rid, callId);
+ if (isMobileDevice()) {
+ callInNewTab();
+ break;
+ }
+ await dispatch({ ongoingCall: { callStatus: CallStatus.IN_PROGRESS_SAME_TAB, time: { time } } });
+ break;
+ }
+ }
+ };
+
+ const declineClick = async () => {
+ await Livechat.updateCallStatus(CallStatus.DECLINED, rid, callId);
+ await Livechat.notifyCallDeclined(rid);
+ await dispatch({
+ incomingCallAlert: null,
+ ongoingCall: {
+ callStatus: CallStatus.DECLINED,
+ time: { time },
+ },
+ });
+ };
+
+ return (
+
+ {
+ show && (
+
+
+
+ { I18n.t('Incoming video Call') }
+
+
+
+
+
+
+ )
+ }
+
+ );
+};
diff --git a/src/components/Calls/CallStatus.js b/src/components/Calls/CallStatus.js
new file mode 100644
index 000000000..d5f4ad851
--- /dev/null
+++ b/src/components/Calls/CallStatus.js
@@ -0,0 +1,12 @@
+export const CallStatus = {
+ RINGING: 'ringing',
+ DECLINED: 'declined',
+ IN_PROGRESS: 'inProgress', // although on Livechat we only use "IN_PROGRESS_SAME_TAB" and "IN_PROGRESS_DIFFERENT_TAB", we still need this status since on Rocket.Chat core, this is the status of ongoing calls
+ IN_PROGRESS_SAME_TAB: 'inProgressSameTab',
+ IN_PROGRESS_DIFFERENT_TAB: 'inProgressDifferentTab',
+ ENDED: 'ended',
+};
+
+export const isCallOngoing = (callStatus) => callStatus === CallStatus.IN_PROGRESS
+ || callStatus === CallStatus.IN_PROGRESS_DIFFERENT_TAB
+ || callStatus === CallStatus.IN_PROGRESS_SAME_TAB;
diff --git a/src/components/Calls/JoinCallButton.js b/src/components/Calls/JoinCallButton.js
new file mode 100644
index 000000000..a24ca88a3
--- /dev/null
+++ b/src/components/Calls/JoinCallButton.js
@@ -0,0 +1,50 @@
+import { h } from 'preact';
+
+import { Livechat } from '../../api';
+import I18n from '../../i18n';
+import VideoIcon from '../../icons/video.svg';
+import constants from '../../lib/constants';
+import store from '../../store';
+import { Button } from '../Button';
+import { createClassName } from '../helpers';
+import { isCallOngoing } from './CallStatus';
+import styles from './styles.scss';
+
+
+export const JoinCallButton = (props) => {
+ const { token, room } = store.state;
+
+ const clickJoinCall = () => {
+ switch (props.callProvider) {
+ case constants.jitsiCallStartedMessageType: {
+ window.open(props.url, room._id);
+ break;
+ }
+ case constants.webRTCCallStartedMessageType: {
+ window.open(`${ Livechat.client.host }/meet/${ room._id }?token=${ token }`, room._id);
+ break;
+ }
+ }
+ };
+ return (
+
+ {
+ isCallOngoing(props.callStatus)
+ && (
+
+
+
+
+
+ { I18n.t('Join my room to start the video call') }
+
+
+
+ )
+ }
+
+ );
+};
diff --git a/src/components/Calls/styles.scss b/src/components/Calls/styles.scss
new file mode 100644
index 000000000..333655e58
--- /dev/null
+++ b/src/components/Calls/styles.scss
@@ -0,0 +1,128 @@
+@import '../../styles/colors';
+@import '../../styles/variables';
+
+.call-notification {
+ position: relative;
+
+ display: flex;
+
+ width: 100%;
+ height: 50%;
+
+ &__content {
+ display: flex;
+ flex-direction: column;
+
+ width: 100%;
+ height: 100%;
+
+ background: #1f2329;
+
+ font-weight: 600;
+ justify-content: space-evenly;
+
+ &-avatar {
+ display: flex;
+
+ margin: 0 auto;
+ align-self: flex-end;
+ }
+
+ &-message {
+ margin: 0 auto;
+
+ color: #ffffff;
+ }
+
+ &-actions {
+ display: flex;
+ flex-direction: row;
+
+ margin: 0 auto;
+ margin-bottom: 15px;
+
+ color: white;
+
+ align-items: flex-end;
+
+ > button {
+ margin-bottom: 0;
+ margin-left: 10px;
+ }
+
+ &-accept {
+ border-color: green;
+ background-color: #2de0a5;
+ }
+
+ &-decline {
+ border-color: red;
+ background-color: #f5455c;
+ }
+ }
+ }
+}
+
+.call-iframe {
+ position: absolute;
+ top: 0;
+
+ width: 100%;
+ height: 41%;
+
+ &__content {
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.joinCall {
+ width: 300px;
+ margin: 15px;
+
+ padding: 5px;
+
+ border: 1px solid #e4e7ea;
+
+ &__content {
+ display: flex;
+ flex-direction: row;
+
+ padding: 15px;
+
+ line-height: 16px;
+ justify-content: space-around;
+
+ &-videoIcon {
+ display: flex;
+
+ height: 7%;
+ margin-right: 10px;
+
+ padding: 5px;
+
+ border: 1px solid white;
+ background-color: #d1ebfe;
+ }
+
+ &-action {
+ display: block;
+
+ width: 120px;
+ margin-top: 0;
+ margin-bottom: 3%;
+ margin-left: 20%;
+ padding: 5px;
+
+ color: white;
+ border: 1px solid blue;
+ background-color: #1d74f5;
+ }
+ }
+}
+
+@media screen and (min-width: 410px) {
+ .joinCall {
+ margin-left: 3%;
+ }
+}
diff --git a/src/components/Messages/Message/index.js b/src/components/Messages/Message/index.js
index 582b9e167..6bb44ee32 100644
--- a/src/components/Messages/Message/index.js
+++ b/src/components/Messages/Message/index.js
@@ -1,7 +1,10 @@
+import { formatDistance } from 'date-fns';
+import format from 'date-fns/format';
+import isToday from 'date-fns/isToday';
import { h } from 'preact';
import I18n from '../../../i18n';
-import { getAttachmentUrl, memo, normalizeTransferHistoryMessage } from '../../helpers';
+import { getAttachmentUrl, memo, normalizeTransferHistoryMessage, resolveDate } from '../../helpers';
import { AudioAttachment } from '../AudioAttachment';
import { FileAttachment } from '../FileAttachment';
import { ImageAttachment } from '../ImageAttachment';
@@ -23,6 +26,7 @@ import {
MESSAGE_TYPE_LIVECHAT_CLOSED,
MESSAGE_TYPE_LIVECHAT_STARTED,
MESSAGE_TYPE_LIVECHAT_TRANSFER_HISTORY,
+ MESSAGE_WEBRTC_CALL,
} from '../constants';
const renderContent = ({
@@ -80,7 +84,16 @@ const renderContent = ({
),
].filter(Boolean);
-const getSystemMessageText = ({ t, conversationFinishedMessage, transferData, u }) =>
+
+const resolveWebRTCEndCallMessage = ({ webRtcCallEndTs, ts }) => {
+ const callEndTime = resolveDate(webRtcCallEndTs);
+ const callStartTime = resolveDate(ts);
+ const callDuration = formatDistance(callEndTime, callStartTime);
+ const time = format(callEndTime, isToday(callEndTime) ? 'HH:mm' : 'dddd HH:mm');
+ return `${ I18n.t('Call ended at %{time}', { time }) } ${ I18n.t(' - Lasted %{callDuration}', { callDuration }) }`;
+};
+
+const getSystemMessageText = ({ t, conversationFinishedMessage, transferData, u, webRtcCallEndTs, ts }) =>
(t === MESSAGE_TYPE_ROOM_NAME_CHANGED && I18n.t('Room name changed'))
|| (t === MESSAGE_TYPE_USER_ADDED && I18n.t('User added by'))
|| (t === MESSAGE_TYPE_USER_REMOVED && I18n.t('User removed by'))
@@ -89,7 +102,8 @@ const getSystemMessageText = ({ t, conversationFinishedMessage, transferData, u
|| (t === MESSAGE_TYPE_WELCOME && I18n.t('Welcome'))
|| (t === MESSAGE_TYPE_LIVECHAT_CLOSED && (conversationFinishedMessage || I18n.t('Conversation finished')))
|| (t === MESSAGE_TYPE_LIVECHAT_STARTED && I18n.t('Chat started'))
- || (t === MESSAGE_TYPE_LIVECHAT_TRANSFER_HISTORY && normalizeTransferHistoryMessage(transferData, u));
+ || (t === MESSAGE_TYPE_LIVECHAT_TRANSFER_HISTORY && normalizeTransferHistoryMessage(transferData, u))
+ || (t === MESSAGE_WEBRTC_CALL && webRtcCallEndTs && ts && resolveWebRTCEndCallMessage({ webRtcCallEndTs, ts }));
const getMessageUsernames = (compact, message) => {
if (compact || !message.u) {
@@ -108,7 +122,6 @@ export const Message = memo(({
avatarResolver,
attachmentResolver = getAttachmentUrl,
use,
- ts,
me,
compact,
className,
@@ -140,6 +153,6 @@ export const Message = memo(({
attachmentResolver,
})}
- {!compact && !message.t && }
+ {!compact && !message.t && }
));
diff --git a/src/components/Messages/MessageList/index.js b/src/components/Messages/MessageList/index.js
index ff5f8ddce..914200780 100644
--- a/src/components/Messages/MessageList/index.js
+++ b/src/components/Messages/MessageList/index.js
@@ -2,13 +2,16 @@ import { parseISO } from 'date-fns/fp';
import isSameDay from 'date-fns/isSameDay';
import { h } from 'preact';
+import constants from '../../../lib/constants';
+import store from '../../../store';
+import { isCallOngoing } from '../../Calls/CallStatus';
+import { JoinCallButton } from '../../Calls/JoinCallButton';
import { createClassName, getAttachmentUrl, MemoizedComponent } from '../../helpers';
import { Message } from '../Message';
import { MessageSeparator } from '../MessageSeparator';
import { TypingIndicator } from '../TypingIndicator';
import styles from './styles.scss';
-
export class MessageList extends MemoizedComponent {
static defaultProps = {
typingUsernames: [],
@@ -106,12 +109,25 @@ export class MessageList extends MemoizedComponent {
typingUsernames,
}) => {
const items = [];
+ const { incomingCallAlert } = store.state;
+ const { ongoingCall } = store.state;
for (let i = 0; i < messages.length; ++i) {
const previousMessage = messages[i - 1];
const message = messages[i];
const nextMessage = messages[i + 1];
+ if ((message.t === constants.webRTCCallStartedMessageType || message.t === constants.jitsiCallStartedMessageType)
+ && message.actionLinks && message.actionLinks.length
+ && ongoingCall && isCallOngoing(ongoingCall.callStatus)
+ && !message.webRtcCallEndTs) {
+ const { url, callProvider, rid } = incomingCallAlert || {};
+ items.push(
+ ,
+ );
+ continue;
+ }
+
const showDateSeparator = !previousMessage || !isSameDay(parseISO(message.ts), parseISO(previousMessage.ts));
if (showDateSeparator) {
items.push(
diff --git a/src/components/Messages/constants.js b/src/components/Messages/constants.js
index 94be2ca13..e4a0d92f5 100644
--- a/src/components/Messages/constants.js
+++ b/src/components/Messages/constants.js
@@ -7,3 +7,5 @@ export const MESSAGE_TYPE_WELCOME = 'wm';
export const MESSAGE_TYPE_LIVECHAT_CLOSED = 'livechat-close';
export const MESSAGE_TYPE_LIVECHAT_STARTED = 'livechat-started';
export const MESSAGE_TYPE_LIVECHAT_TRANSFER_HISTORY = 'livechat_transfer_history';
+export const MESSAGE_JITSI_CALL = 'jitsi_call_started';
+export const MESSAGE_WEBRTC_CALL = 'livechat_webrtc_video_call';
diff --git a/src/components/helpers.js b/src/components/helpers.js
index 06d1d040b..57f467b00 100644
--- a/src/components/helpers.js
+++ b/src/components/helpers.js
@@ -1,3 +1,4 @@
+import parseISO from 'date-fns/parseISO';
import { Component } from 'preact';
import { Livechat, useSsl } from '../api';
@@ -136,6 +137,7 @@ export const sortArrayByColumn = (array, column, inverted) => array.sort((a, b)
return 1;
});
+
export const normalizeTransferHistoryMessage = (transferData, sender) => {
if (!transferData) {
return;
@@ -173,7 +175,6 @@ export const parseOfflineMessage = (fields = {}) => {
};
export const normalizeDOMRect = ({ left, top, right, bottom }) => ({ left, top, right, bottom });
-
export const visibility = (() => {
if (typeof document.hidden !== 'undefined') {
return {
@@ -244,3 +245,22 @@ export const isActiveSession = () => {
return sessionId === firstSessionId;
};
+
+export const isMobileDevice = () => window.innerWidth <= 800 && window.innerHeight >= 630;
+
+export const resolveDate = (dateInput) => {
+ switch (typeof dateInput) {
+ case Date: {
+ return dateInput;
+ }
+ case 'object': {
+ return new Date(dateInput.$date);
+ }
+ case 'string': {
+ return parseISO(dateInput);
+ }
+ default: {
+ return new Date(dateInput);
+ }
+ }
+};
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 8df1c29eb..77138ed2c 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -24,6 +24,7 @@
"drop_here_to_upload_a_file_e5f4dd60": "Drop here to upload a file",
"email_22a7d52d": "Email",
"enable_notifications_a3daf4b1": "Enable notifications",
+ "error_getting_call_alert": "Error occurred while receiving a call notification",
"error_closing_chat_4c5e29d7": "Error closing chat.",
"error_removing_user_data_ce507478": "Error removing user data.",
"error_starting_a_new_conversation_reason_a1b491a1": "Error starting a new conversation: %{reason}",
@@ -37,6 +38,8 @@
"from_transferred_the_chat_to_the_department_to_752ab298": "%{from} transferred the chat to the department %{to}",
"from_transferred_the_chat_to_to_15bdcb11": "%{from} transferred the chat to %{to}",
"gdpr_8b366c2b": "GDPR",
+ "call_start_time": "Call Started at %{time}",
+ "call_end_time": "Call Ended at %{time}",
"go_to_menu_options_forget_remove_my_personal_data__99c40934": "Go to **menu options → Forget/Remove my personal data** to request the immediate removal of your data.",
"hiddenelementscount_more_c017d614": "+ %{hiddenElementsCount} more",
"i_agree_df2ecbd4": "I Agree",
@@ -88,4 +91,4 @@
"your_spot_is_spot_a35cd288": "Your spot is #%{spot}",
"your_spot_is_spot_estimated_wait_time_estimatedwai_d0ff46e0": "Your spot is #%{spot} (Estimated wait time: %{estimatedWaitTime})"
}
-}
\ No newline at end of file
+}
diff --git a/src/icons/phone.svg b/src/icons/phone.svg
new file mode 100644
index 000000000..074a7c13c
--- /dev/null
+++ b/src/icons/phone.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/src/icons/phoneOff.svg b/src/icons/phoneOff.svg
new file mode 100644
index 000000000..a92af93a4
--- /dev/null
+++ b/src/icons/phoneOff.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/icons/video.svg b/src/icons/video.svg
new file mode 100644
index 000000000..e735cfab1
--- /dev/null
+++ b/src/icons/video.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/icons/videoIcon.svg b/src/icons/videoIcon.svg
new file mode 100644
index 000000000..e735cfab1
--- /dev/null
+++ b/src/icons/videoIcon.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/lib/constants.js b/src/lib/constants.js
index 014215c02..717175546 100644
--- a/src/lib/constants.js
+++ b/src/lib/constants.js
@@ -4,4 +4,6 @@ export default {
livechatConnectedAlertId: 'LIVECHAT_CONNECTED',
livechatDisconnectedAlertId: 'LIVECHAT_DISCONNECTED',
livechatQueueMessageId: 'LIVECHAT_QUEUE_MESSAGE',
+ webRTCCallStartedMessageType: 'livechat_webrtc_video_call',
+ jitsiCallStartedMessageType: 'jitsi_call_started',
};
diff --git a/src/lib/room.js b/src/lib/room.js
index e4e6c0e0b..6d742d947 100644
--- a/src/lib/room.js
+++ b/src/lib/room.js
@@ -1,15 +1,19 @@
import { route } from 'preact-router';
import { Livechat } from '../api';
-import { setCookies, upsert, canRenderMessage } from '../components/helpers';
+import { CallStatus, isCallOngoing } from '../components/Calls/CallStatus';
+import { setCookies, upsert, canRenderMessage, createToken } from '../components/helpers';
+import I18n from '../i18n';
import { store } from '../store';
import { normalizeAgent } from './api';
import Commands from './commands';
+import constants from './constants';
import { loadConfig, processUnread } from './main';
import { parentCall } from './parentCall';
import { normalizeMessage, normalizeMessages } from './threads';
import { handleTranscript } from './transcript';
+
const commands = new Commands();
export const closeChat = async ({ transcriptRequested } = {}) => {
@@ -22,11 +26,41 @@ export const closeChat = async ({ transcriptRequested } = {}) => {
route('/chat-finished');
};
+// TODO: use a separate event to listen to call start event. Listening on the message type isn't a good solution
+export const processIncomingCallMessage = async (message) => {
+ const { alerts } = store.state;
+ try {
+ await store.setState({
+ incomingCallAlert: {
+ show: true,
+ callProvider: message.t,
+ callerUsername: message.u.username,
+ rid: message.rid,
+ time: message.ts,
+ callId: message._id,
+ url: message.t === constants.jitsiCallStartedMessageType ? message.customFields.jitsiCallUrl : '',
+ },
+ ongoingCall: {
+ callStatus: CallStatus.RINGING,
+ time: message.ts,
+ },
+ });
+ } catch (err) {
+ console.error(err);
+ const alert = { id: createToken(), children: I18n.t('error_getting_call_alert'), error: true, timeout: 5000 };
+ await store.setState({ alerts: (alerts.push(alert), alerts) });
+ }
+};
+
const processMessage = async (message) => {
if (message.t === 'livechat-close') {
closeChat(message);
} else if (message.t === 'command') {
commands[message.msg] && commands[message.msg]();
+ } else if (message.webRtcCallEndTs) {
+ await store.setState({ ongoingCall: { callStatus: CallStatus.ENDED, time: message.ts }, incomingCallAlert: null });
+ } else if (message.t === constants.webRTCCallStartedMessageType || message.t === constants.jitsiCallStartedMessageType) {
+ await processIncomingCallMessage(message);
}
};
@@ -152,11 +186,13 @@ Livechat.onMessage(async (message) => {
});
export const getGreetingMessages = (messages) => messages && messages.filter((msg) => msg.trigger);
+export const getLatestCallMessage = (messages) => messages && messages.filter((msg) => msg.t === constants.webRTCCallStartedMessageType || msg.t === constants.jitsiCallStartedMessageType).pop();
export const loadMessages = async () => {
- const { messages: storedMessages, room: { _id: rid } = {} } = store.state;
- const previousMessages = getGreetingMessages(storedMessages);
+ const { ongoingCall } = store.state;
+ const { messages: storedMessages, room: { _id: rid, callStatus } = {} } = store.state;
+ const previousMessages = getGreetingMessages(storedMessages);
if (!rid) {
return;
}
@@ -172,6 +208,48 @@ export const loadMessages = async () => {
const lastMessage = messages[messages.length - 1];
await store.setState({ lastReadMessageId: lastMessage && lastMessage._id });
}
+
+ if (ongoingCall && isCallOngoing(ongoingCall.callStatus)) {
+ return;
+ }
+
+ const latestCallMessage = getLatestCallMessage(messages);
+ if (!latestCallMessage) {
+ return;
+ }
+ if (latestCallMessage.t === constants.jitsiCallStartedMessageType) {
+ await store.setState({
+ ongoingCall: {
+ callStatus: CallStatus.IN_PROGRESS_DIFFERENT_TAB,
+ time: latestCallMessage.ts,
+ },
+ incomingCallAlert: {
+ show: false,
+ callProvider:
+ latestCallMessage.t,
+ url: latestCallMessage.customFields.jitsiCallUrl,
+ },
+ });
+ return;
+ }
+ switch (callStatus) {
+ case CallStatus.IN_PROGRESS: {
+ await store.setState({
+ ongoingCall: {
+ callStatus: CallStatus.IN_PROGRESS_DIFFERENT_TAB,
+ time: latestCallMessage.ts,
+ },
+ incomingCallAlert: {
+ show: false,
+ callProvider: latestCallMessage.t,
+ },
+ });
+ break;
+ }
+ case CallStatus.RINGING: {
+ processIncomingCallMessage(latestCallMessage);
+ }
+ }
};
export const loadMoreMessages = async () => {
diff --git a/src/routes/Chat/component.js b/src/routes/Chat/component.js
index 0fa0774b3..dfc3cf196 100644
--- a/src/routes/Chat/component.js
+++ b/src/routes/Chat/component.js
@@ -2,6 +2,9 @@ import { Picker } from 'emoji-mart';
import { h, Component } from 'preact';
import { Button } from '../../components/Button';
+import { CallIframe } from '../../components/Calls/CallIFrame';
+import { CallNotification } from '../../components/Calls/CallNotification';
+import { CallStatus } from '../../components/Calls/CallStatus';
import { Composer, ComposerAction, ComposerActions } from '../../components/Composer';
import { FilesDropTarget } from '../../components/FilesDropTarget';
import { FooterOptions, CharCounter } from '../../components/Footer';
@@ -118,6 +121,9 @@ export default class Chat extends Component {
registrationRequired,
onRegisterUser,
limitTextLength,
+ incomingCallAlert,
+ ongoingCall,
+ dispatch,
...props
}, {
atBottom = true,
@@ -144,6 +150,8 @@ export default class Chat extends Component {
onUpload={onUpload}
>
+ { incomingCallAlert && !!incomingCallAlert.show && }
+ { incomingCallAlert?.show && ongoingCall && ongoingCall.callStatus === CallStatus.IN_PROGRESS_SAME_TAB ? : null }
(
lastReadMessageId,
triggerAgent,
queueInfo,
+ incomingCallAlert,
+ ongoingCall,
}) => (
(
nameFieldRegistrationForm={nameFieldRegistrationForm}
emailFieldRegistrationForm={emailFieldRegistrationForm}
limitTextLength={limitTextLength}
+ incomingCallAlert={incomingCallAlert}
+ ongoingCall={ongoingCall}
/>
)}
diff --git a/src/store/index.js b/src/store/index.js
index 47d031d06..fdbc7b13e 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -34,9 +34,11 @@ const initialState = {
visible: true,
minimized: true,
unread: null,
+ incomingCallAlert: null,
+ ongoingCall: null, // TODO: store call info like url, startTime, timeout, etc here
};
-const dontPersist = ['messages', 'typing', 'loading', 'alerts', 'unread', 'noMoreMessages', 'modal'];
+const dontPersist = ['messages', 'typing', 'loading', 'alerts', 'unread', 'noMoreMessages', 'modal', 'incomingCallAlert', 'ongoingCall'];
export const store = new Store(initialState, { dontPersist });
if (process.env.NODE_ENV === 'development') {
diff --git a/yarn.lock b/yarn.lock
index e56d84160..438d8b101 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1598,10 +1598,10 @@
dependencies:
eslint-plugin-import "^2.17.2"
-"@rocket.chat/sdk@^1.0.0-alpha.41":
- version "1.0.0-alpha.41"
- resolved "https://registry.yarnpkg.com/@rocket.chat/sdk/-/sdk-1.0.0-alpha.41.tgz#8fcae2885786bec56a56b6d9a8cccaa365b77364"
- integrity sha512-jQ+/exEQMOv+bwH+yzPTC0oJGIKj/AlMc95IvWAn/vHDLjjS3aGzpIpZhBwsMOBVvb/5N8rnq6kEleCkEJk28g==
+"@rocket.chat/sdk@^1.0.0-alpha.42":
+ version "1.0.0-alpha.42"
+ resolved "https://registry.yarnpkg.com/@rocket.chat/sdk/-/sdk-1.0.0-alpha.42.tgz#e3adc7ee245c6947fe368c0d3b8494c5a97c0673"
+ integrity sha512-e3roTprM3UhlXOym2kN8o2doN1vBBS23obZgupPitecZWpK8eQghLk78a4L4uDAqBwFZ65Xphs3L1gaPSZJARQ==
dependencies:
js-sha256 "^0.9.0"
lru-cache "^4.1.1"