Skip to content
This repository has been archived by the owner on Jun 30, 2022. It is now read-only.

Commit

Permalink
add callnotification,callStartmsg,iframe code (#617)
Browse files Browse the repository at this point in the history
* add callnotification,msg,iframe code

* fix eslint issues

* fix eslint file path issues

* fix stylelint issues

* done ui changes

* add icons and improve ui

* fix error

* remove-icons

* add icons

* add i18n.t, change classname, improve ui

* remove font-family

* change iframe link

* add check for jitsi

* add jitsi link

* add time message in system message and add catch

* display alert, change function name

* Improve overall codebase

* Convert tabs to spaces for translation file

* Accept jitsi url info from the message and remove dependency from Livechat.videoCall endpoint

* Update index.js

* add message in i18n file

Co-authored-by: Murtaza Patrawala <34130764+murtaza98@users.noreply.github.com>
  • Loading branch information
Deepak-learner and murtaza98 committed Nov 16, 2021
1 parent cb24408 commit 14c4d17
Show file tree
Hide file tree
Showing 17 changed files with 244 additions and 6 deletions.
Binary file modified .loki/reference/chrome_Components_Icons_all.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .loki/reference/chrome_Components_Icons_phone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/components/Calls/CallIFrame.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { h } from 'preact';

import { Screen } from '../Screen';
import { createClassName } from '../helpers';
import styles from './styles.scss';


export const CallIFrame = (url) => (
<Screen.Content nopadding>
<div className={createClassName(styles, 'call-iframe')}>
<iframe className={createClassName(styles, 'call-iframe__content')} src={url} />
</div>
</Screen.Content>
);
64 changes: 64 additions & 0 deletions src/components/Calls/CallNotification.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { h } from 'preact';
import { useState } from 'preact/compat';

import I18n from '../../i18n';
import PhoneAccept from '../../icons/phone.svg';
import PhoneDecline from '../../icons/phoneOff.svg';
import constants from '../../lib/constants';
import { Avatar } from '../Avatar';
import { Button } from '../Button';
import { createClassName, getAvatarUrl } from '../helpers';
import styles from './styles.scss';


export const CallNotification = ({ callProvider, callerUsername, url, dispatch } = { callProvider: undefined, callerUsername: undefined, dispatch: undefined }) => {
const [show, setShow] = useState(!!callProvider && !!callerUsername && !!dispatch && !!url);

const acceptClick = async () => {
setShow(!{ show });

switch (callProvider) {
case constants.jitsiCallStartedMessageType: {
window.open(url);
await dispatch({ incomingCallAlert: null });
break;
}
case constants.webrtcCallStartedMessageType: {
// TODO: add webrtc code here
break;
}
}
};

const declineClick = async () => {
await dispatch({ incomingCallAlert: null });
};

return (
<div className={createClassName(styles, 'call-notification')}>
{ show
? (
<div className={createClassName(styles, 'call-notification__content')}>
<div className={createClassName(styles, 'call-notification__content-avatar')}>
<Avatar
src={getAvatarUrl(callerUsername)}
large
/>
</div>
<div className={createClassName(styles, 'call-notification__content-message')}>
{ I18n.t('Incoming video Call') }
</div>
<div className={createClassName(styles, 'call-notification__content-actions')}>
<Button onClick={declineClick} className={createClassName(styles, 'call-notification__content-actions-accept')}>
<PhoneDecline width={20} height={20} /> <span style='margin-left:5px'> {I18n.t('Decline')} </span>
</Button>
<Button onClick={acceptClick} className={createClassName(styles, 'call-notification__content-actions-decline')} >
<PhoneAccept width={20} height={20} /><span style='margin-left:5px'> {I18n.t('Accept')} </span>
</Button>
</div>
</div>
)
: null
}
</div>);
};
78 changes: 78 additions & 0 deletions src/components/Calls/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
@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: relative;
top: 0;

display: flex;

width: 100%;
height: 50%;

&__content {
height: 100%;
}
}
10 changes: 8 additions & 2 deletions src/components/Messages/Message/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { h } from 'preact';

import I18n from '../../../i18n';
import { getAttachmentUrl, memo, normalizeTransferHistoryMessage } from '../../helpers';
import { getAttachmentUrl, memo, normalizeTransferHistoryMessage, normalizeCallTimeMessage } from '../../helpers';
import { AudioAttachment } from '../AudioAttachment';
import { FileAttachment } from '../FileAttachment';
import { ImageAttachment } from '../ImageAttachment';
Expand All @@ -22,6 +22,8 @@ import {
MESSAGE_TYPE_WELCOME,
MESSAGE_TYPE_LIVECHAT_CLOSED,
MESSAGE_TYPE_LIVECHAT_STARTED,
MESSAGE_WEBRTC_CALL,
MESSAGE_JITSI_CALL,
MESSAGE_TYPE_LIVECHAT_TRANSFER_HISTORY,
} from '../constants';

Expand Down Expand Up @@ -80,7 +82,8 @@ const renderContent = ({
),
].filter(Boolean);

const getSystemMessageText = ({ t, conversationFinishedMessage, transferData, u }) =>

const getSystemMessageText = ({ t, conversationFinishedMessage, transferData, u, callStatus }) =>
(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'))
Expand All @@ -89,8 +92,11 @@ 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_WEBRTC_CALL && normalizeCallTimeMessage(callStatus))
|| (t === MESSAGE_JITSI_CALL && normalizeCallTimeMessage(callStatus))
|| (t === MESSAGE_TYPE_LIVECHAT_TRANSFER_HISTORY && normalizeTransferHistoryMessage(transferData, u));


const getMessageUsernames = (compact, message) => {
if (compact || !message.u) {
return [];
Expand Down
2 changes: 2 additions & 0 deletions src/components/Messages/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 'webrtc_call_started';
export const MESSAGE_WEBRTC_CALL = 'jitsi_call_started';
19 changes: 18 additions & 1 deletion src/components/helpers.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import format from 'date-fns/format';
import { parseISO } from 'date-fns/fp';
import isToday from 'date-fns/isToday';
import { Component } from 'preact';

import { Livechat, useSsl } from '../api';
Expand Down Expand Up @@ -123,7 +126,7 @@ export const createToken = () => Math.random().toString(36).substring(2, 15) + M

export const getAvatarUrl = (username) => (username ? `${ Livechat.client.host }/avatar/${ username }` : null);

export const msgTypesNotRendered = ['livechat_video_call', 'livechat_navigation_history', 'au', 'command', 'uj', 'ul', 'livechat-close'];
export const msgTypesNotRendered = ['livechat_video_call', 'livechat_navigation_history', 'au', 'command', 'uj', 'ul', 'livechat-close', 'webRTC_call_started', 'jitsi_call_started'];

export const canRenderMessage = ({ t }) => !msgTypesNotRendered.includes(t);

Expand All @@ -136,6 +139,20 @@ export const sortArrayByColumn = (array, column, inverted) => array.sort((a, b)
return 1;
});

export const normalizeCallTimeMessage = (callStatus) => {
const timestamp = new Date().toISOString();
const time = format(parseISO(timestamp), isToday(parseISO(timestamp)) ? 'HH:mm' : 'dddd HH:mm');
if (!callStatus) {
return;
}
if (callStatus === 'accept') {
return I18n.t('call_start_time', { time });
}
if (callStatus === 'endCall') {
return I18n.t('call_end_time', { time });
}
};

export const normalizeTransferHistoryMessage = (transferData, sender) => {
if (!transferData) {
return;
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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}",
Expand All @@ -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",
Expand Down Expand Up @@ -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})"
}
}
}
6 changes: 6 additions & 0 deletions src/icons/phone.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/icons/phoneOff.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ export default {
livechatConnectedAlertId: 'LIVECHAT_CONNECTED',
livechatDisconnectedAlertId: 'LIVECHAT_DISCONNECTED',
livechatQueueMessageId: 'LIVECHAT_QUEUE_MESSAGE',
webrtcCallStartedMessageType: 'webRTC_call_started',
jitsiCallStartedMessageType: 'jitsi_call_started',
};
35 changes: 34 additions & 1 deletion src/lib/room.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { route } from 'preact-router';

import { Livechat } from '../api';
import { setCookies, upsert, canRenderMessage } from '../components/helpers';
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 } = {}) => {
Expand All @@ -22,11 +25,36 @@ 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 processCallMessage = async (message) => {
const { alerts } = store.state;
try {
await store.setState({ incomingCallAlert: {
show: true,
callProvider: message.t,
callerUsername: message.u.username,
...message.customFields.jitsiCallUrl && { url: message.customFields.jitsiCallUrl },
} });
} 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) => {
const { incomingCallAlert } = store.state;
if (incomingCallAlert) {
// TODO: create a new event to handle the call dismiss event, currently we're just dismissing the call alert if a new message is sent which is not a good solution
await store.setState({ incomingCallAlert: null });
}

if (message.t === 'livechat-close') {
closeChat(message);
} else if (message.t === 'command') {
commands[message.msg] && commands[message.msg]();
} else if (message.t === constants.webrtcCallStartedMessageType || message.t === constants.jitsiCallStartedMessageType) {
await processCallMessage(message);
}
};

Expand Down Expand Up @@ -171,6 +199,11 @@ export const loadMessages = async () => {
if (messages && messages.length) {
const lastMessage = messages[messages.length - 1];
await store.setState({ lastReadMessageId: lastMessage && lastMessage._id });

// TODO: create a separate event for starting the call and checking if the call is ongoing
if (lastMessage.t === constants.webrtcCallStartedMessageType || lastMessage.t === constants.jitsiCallStartedMessageType) {
await processCallMessage(lastMessage);
}
}
};

Expand Down
4 changes: 4 additions & 0 deletions src/routes/Chat/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Picker } from 'emoji-mart';
import { h, Component } from 'preact';

import { Button } from '../../components/Button';
import { CallNotification } from '../../components/Calls/CallNotification';
import { Composer, ComposerAction, ComposerActions } from '../../components/Composer';
import { FilesDropTarget } from '../../components/FilesDropTarget';
import { FooterOptions, CharCounter } from '../../components/Footer';
Expand Down Expand Up @@ -118,6 +119,8 @@ export default class Chat extends Component {
registrationRequired,
onRegisterUser,
limitTextLength,
incomingCallAlert,
dispatch,
...props
}, {
atBottom = true,
Expand All @@ -144,6 +147,7 @@ export default class Chat extends Component {
onUpload={onUpload}
>
<Screen.Content nopadding>
{ incomingCallAlert && !!incomingCallAlert.show && <CallNotification { ...incomingCallAlert } dispatch={dispatch} />}
<div className={createClassName(styles, 'chat__messages', { atBottom, loading })}>
<MessageList
ref={this.handleMessagesContainerRef}
Expand Down
2 changes: 2 additions & 0 deletions src/routes/Chat/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ export const ChatConnector = ({ ref, ...props }) => (
lastReadMessageId,
triggerAgent,
queueInfo,
incomingCallAlert,
}) => (
<ChatContainer
ref={ref}
Expand Down Expand Up @@ -456,6 +457,7 @@ export const ChatConnector = ({ ref, ...props }) => (
nameFieldRegistrationForm={nameFieldRegistrationForm}
emailFieldRegistrationForm={emailFieldRegistrationForm}
limitTextLength={limitTextLength}
incomingCallAlert={incomingCallAlert}
/>
)}
</Consumer>
Expand Down
Loading

0 comments on commit 14c4d17

Please sign in to comment.