Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions client/lib/voip/QueueAggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class QueueAggregator {
// Maintains the history of the queue that the agent has served
private sessionQueueCallServingHistory: IQueueServingRecord[];

private currentlyServing: IQueueServingRecord | undefined;
private currentlyServing: IQueueServingRecord;

private currentQueueMembershipStatus: Record<string, IQueueInfo>;

Expand Down Expand Up @@ -97,17 +97,24 @@ export class QueueAggregator {
return totalCallWaitingCount;
}

callRinging(queueInfo: { queuename: string; callerId: { id: string; name: string } }): void {
getCurrentQueueName(): string {
if (this.currentlyServing.queueInfo) {
return this.currentlyServing.queueInfo.queueName;
}

return '';
}

callRinging(queueInfo: { queuename: string; callerid: { id: string; name: string } }): void {
if (!this.currentQueueMembershipStatus[queueInfo.queuename]) {
// something is wrong. Queue is not found in the membership details.
return;
}

const queueServing: IQueueServingRecord = {
queueInfo: this.currentQueueMembershipStatus[queueInfo.queuename],
callerId: {
callerId: queueInfo.callerId.id,
callerName: queueInfo.callerId.name,
callerId: queueInfo.callerid.id,
callerName: queueInfo.callerid.name,
},
callStarted: undefined,
callEnded: undefined,
Expand Down
4 changes: 2 additions & 2 deletions client/lib/voip/VoIPUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class VoIPUser extends Emitter<VoipEvents> implements OutgoingRequestDele

private mode: WorkflowTypes;

private queueInfo?: QueueAggregator;
private queueInfo: QueueAggregator;

get callState(): CallStates {
return this._callState;
Expand Down Expand Up @@ -649,7 +649,7 @@ export class VoIPUser extends Emitter<VoipEvents> implements OutgoingRequestDele
this.queueInfo?.setMembership(subscription);
}

getAggregator(): QueueAggregator | undefined {
getAggregator(): QueueAggregator {
return this.queueInfo;
}

Expand Down
113 changes: 47 additions & 66 deletions client/providers/CallProvider/CallProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import { useEndpoint, useStream } from '../../contexts/ServerContext';
import { useSetting } from '../../contexts/SettingsContext';
import { useUser } from '../../contexts/UserContext';
import { roomCoordinator } from '../../lib/rooms/roomCoordinator';
import { isUseVoipClientResultError, isUseVoipClientResultLoading, useVoipClient } from './hooks/useVoipClient';
import { QueueAggregator } from '../../lib/voip/QueueAggregator';
import { useVoipClient } from './hooks/useVoipClient';

const startRingback = (user: IUser): void => {
const audioVolume = getUserPreference(user, 'notificationsSoundVolume');
Expand Down Expand Up @@ -44,26 +45,44 @@ export const CallProvider: FC = ({ children }) => {

const AudioTagPortal: FC = ({ children }) => useMemo(() => createPortal(children, document.body), [children]);

const [queueName, setQueueName] = useState('');
const [queueCounter, setQueueCounter] = useState(0);
const [queueName, setQueueName] = useState('');

const setModal = useSetModal();

const openWrapUpModal = useCallback((): void => {
setModal(<WrapUpCallModal />);
}, [setModal]);

const [queueAggregator, setQueueAggregator] = useState<QueueAggregator>();

useEffect(() => {
if (!voipEnabled || !user) {
if (!result?.voipClient) {
return;
}

if (isUseVoipClientResultError(result) || isUseVoipClientResultLoading(result)) {
setQueueAggregator(result.voipClient.getAggregator());
}, [result]);

useEffect(() => {
if (!voipEnabled || !user || !queueAggregator) {
return;
}

const queueAggregator = result.voipClient.getAggregator();
if (!queueAggregator) {
const handleAgentCalled = async (queue: {
queuename: string;
callerId: { id: string; name: string };
queuedcalls: string;
}): Promise<void> => {
queueAggregator.callRinging({ queuename: queue.queuename, callerid: queue.callerId });
setQueueName(queueAggregator.getCurrentQueueName());
};

return subscribeToNotifyUser(`${user._id}/agentcalled`, handleAgentCalled);
}, [subscribeToNotifyUser, user, voipEnabled, queueAggregator]);

useEffect(() => {
if (!voipEnabled || !user || !queueAggregator) {
return;
}

Expand All @@ -73,69 +92,42 @@ export const CallProvider: FC = ({ children }) => {
queuedcalls: string;
}): Promise<void> => {
queueAggregator.queueJoined(joiningDetails);
setQueueName(joiningDetails.queuename);
setQueueCounter(queueAggregator.getCallWaitingCount());
};

return subscribeToNotifyUser(`${user._id}/callerjoined`, handleQueueJoined);
}, [result, subscribeToNotifyUser, user, voipEnabled]);
}, [subscribeToNotifyUser, user, voipEnabled, queueAggregator]);

useEffect(() => {
if (!voipEnabled || !user) {
return;
}

if (isUseVoipClientResultError(result) || isUseVoipClientResultLoading(result)) {
return;
}

const queueAggregator = result.voipClient.getAggregator();
if (!queueAggregator) {
if (!voipEnabled || !user || !queueAggregator) {
return;
}

const handleAgentConnected = (queue: { queuename: string; queuedcalls: string; waittimeinqueue: string }): void => {
queueAggregator.callPickedup(queue);
setQueueName(queueAggregator.getCurrentQueueName());
setQueueCounter(queueAggregator.getCallWaitingCount());
};

return subscribeToNotifyUser(`${user._id}/agentconnected`, handleAgentConnected);
}, [result, subscribeToNotifyUser, user, voipEnabled]);
}, [queueAggregator, subscribeToNotifyUser, user, voipEnabled]);

useEffect(() => {
if (!voipEnabled || !user) {
return;
}

if (isUseVoipClientResultError(result) || isUseVoipClientResultLoading(result)) {
return;
}

const queueAggregator = result.voipClient.getAggregator();
if (!queueAggregator) {
if (!voipEnabled || !user || !queueAggregator) {
return;
}

const handleMemberAdded = (queue: { queuename: string; queuedcalls: string }): void => {
queueAggregator.memberAdded(queue);
setQueueName(queue.queuename);
setQueueName(queueAggregator.getCurrentQueueName());
setQueueCounter(queueAggregator.getCallWaitingCount());
};

return subscribeToNotifyUser(`${user._id}/queuememberadded`, handleMemberAdded);
}, [result, subscribeToNotifyUser, user, voipEnabled]);
}, [queueAggregator, subscribeToNotifyUser, user, voipEnabled]);

useEffect(() => {
if (!voipEnabled || !user) {
return;
}

if (isUseVoipClientResultError(result) || isUseVoipClientResultLoading(result)) {
return;
}

const queueAggregator = result.voipClient.getAggregator();
if (!queueAggregator) {
if (!voipEnabled || !user || !queueAggregator) {
return;
}

Expand All @@ -145,48 +137,37 @@ export const CallProvider: FC = ({ children }) => {
};

return subscribeToNotifyUser(`${user._id}/queuememberremoved`, handleMemberRemoved);
}, [result, subscribeToNotifyUser, user, voipEnabled]);
}, [queueAggregator, subscribeToNotifyUser, user, voipEnabled]);

useEffect(() => {
if (!voipEnabled || !user) {
return;
}

if (isUseVoipClientResultError(result) || isUseVoipClientResultLoading(result)) {
return;
}

const queueAggregator = result.voipClient.getAggregator();
if (!queueAggregator) {
if (!voipEnabled || !user || !queueAggregator) {
return;
}

const handleCallAbandon = (queue: { queuename: string; queuedcallafterabandon: string }): void => {
queueAggregator.queueAbandoned(queue);
setQueueName(queueAggregator.getCurrentQueueName());
setQueueCounter(queueAggregator.getCallWaitingCount());
};

return subscribeToNotifyUser(`${user._id}/callabandoned`, handleCallAbandon);
}, [result, subscribeToNotifyUser, user, voipEnabled]);
}, [queueAggregator, subscribeToNotifyUser, user, voipEnabled]);

useEffect(() => {
if (!voipEnabled || !user) {
if (!voipEnabled || !user || !queueAggregator) {
return;
}

const handleCallHangup = (_event: { roomId: string }): void => {
setQueueName(queueAggregator.getCurrentQueueName());
openWrapUpModal();
};

return subscribeToNotifyUser(`${user._id}/call.callerhangup`, handleCallHangup);
}, [openWrapUpModal, result, subscribeToNotifyUser, user, voipEnabled]);
}, [openWrapUpModal, queueAggregator, subscribeToNotifyUser, user, voipEnabled]);

useEffect(() => {
if (isUseVoipClientResultError(result)) {
return;
}

if (isUseVoipClientResultLoading(result)) {
if (!result.voipClient) {
return;
}

Expand Down Expand Up @@ -256,15 +237,15 @@ export const CallProvider: FC = ({ children }) => {
};
}

if (isUseVoipClientResultError(result)) {
if (result.error) {
return {
enabled: true,
ready: false,
error: result.error,
};
}

if (isUseVoipClientResultLoading(result)) {
if (!result.voipClient) {
return {
enabled: true,
ready: false,
Expand All @@ -281,8 +262,8 @@ export const CallProvider: FC = ({ children }) => {
enabled: true,
ready: true,
openedRoomInfo: roomInfo,
registrationInfo,
voipClient,
registrationInfo,
queueCounter,
queueName,
actions: {
Expand All @@ -308,7 +289,7 @@ export const CallProvider: FC = ({ children }) => {
const voipRoom = visitor && (await voipEndpoint({ token: visitor.token, agentId: user._id }));
openRoom(voipRoom.room._id);
voipRoom.room && setRoomInfo({ v: { token: voipRoom.room.v.token }, rid: voipRoom.room._id });
const queueAggregator = result.voipClient.getAggregator();
const queueAggregator = voipClient.getAggregator();
if (queueAggregator) {
queueAggregator.callStarted();
}
Expand All @@ -319,7 +300,7 @@ export const CallProvider: FC = ({ children }) => {
closeRoom: async ({ comment, tags }: { comment: string; tags: string[] }): Promise<void> => {
roomInfo && (await voipCloseRoomEndpoint({ rid: roomInfo.rid, token: roomInfo.v.token || '', comment: comment || '', tags }));
homeRoute.push({});
const queueAggregator = result.voipClient.getAggregator();
const queueAggregator = voipClient.getAggregator();
if (queueAggregator) {
queueAggregator.callEnded();
}
Expand All @@ -328,12 +309,12 @@ export const CallProvider: FC = ({ children }) => {
};
}, [
voipEnabled,
user,
result,
roomInfo,
queueCounter,
queueName,
openWrapUpModal,
user,
visitorEndpoint,
voipEndpoint,
voipCloseRoomEndpoint,
Expand Down
25 changes: 8 additions & 17 deletions client/providers/CallProvider/hooks/useVoipClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,11 @@ import { SimpleVoipUser } from '../../../lib/voip/SimpleVoipUser';
import { VoIPUser } from '../../../lib/voip/VoIPUser';
import { useWebRtcServers } from './useWebRtcServers';

type UseVoipClientResult = UseVoipClientResultResolved | UseVoipClientResultError | UseVoipClientResultLoading;

type UseVoipClientResultResolved = {
voipClient: VoIPUser;
registrationInfo: IRegistrationInfo;
type UseVoipClientResult = {
voipClient?: VoIPUser;
registrationInfo?: IRegistrationInfo;
error?: Error | unknown;
};
type UseVoipClientResultError = { error: Error };
type UseVoipClientResultLoading = Record<string, never>;

export const isUseVoipClientResultError = (result: UseVoipClientResult): result is UseVoipClientResultError =>
!!(result as UseVoipClientResultError).error;

export const isUseVoipClientResultLoading = (result: UseVoipClientResult): result is UseVoipClientResultLoading =>
!result || !Object.keys(result).length;

const isSignedResponse = (data: any): data is { result: string } => typeof data?.result === 'string';

Expand Down Expand Up @@ -69,13 +60,13 @@ export const useVoipClient = (): UseVoipClientResult => {
client.setWorkflowMode(WorkflowTypes.CONTACT_CENTER_USER);
client.setMembershipSubscription(subscription);
setResult({ voipClient: client, registrationInfo: parsedData });
} catch (e) {
setResult({ error: e as Error });
} catch (error) {
setResult({ error });
}
})();
},
(error) => {
setResult({ error: error as Error });
(error: Error) => {
setResult({ error });
},
);
return (): void => {
Expand Down
2 changes: 1 addition & 1 deletion client/sidebar/footer/voip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const VoipFooter = (): ReactElement | null => {
case 'IN_CALL':
return t('In_progress');
case 'OFFER_RECEIVED':
return t('Calling');
return t('Ringing');
case 'ON_HOLD':
return t('On_Hold');
}
Expand Down
9 changes: 5 additions & 4 deletions packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -714,9 +714,9 @@
"Call": "Call",
"Calling": "Calling",
"Call_Center": "Call Center",
"Calls_in_queue": "__calls__ Call In Queue",
"Calls_in_queue_plural": "__calls__ Calls In Queue",
"Calls_in_queue_empty": "Queue Is Empty",
"Calls_in_queue": "__calls__ call in queue",
"Calls_in_queue_plural": "__calls__ calls in queue",
"Calls_in_queue_empty": "Queue is empty",
"Call_declined": "Call Declined!",
"Call_Information": "Call Information",
"Call_provider": "Call Provider",
Expand Down Expand Up @@ -3270,7 +3270,7 @@
"Omnichannel_External_Frame_Encryption_JWK_Description": "If provided it will encrypt the user's token with the provided key and the external system will need to decrypt the data to access the token",
"Omnichannel_External_Frame_URL": "External frame URL",
"On": "On",
"On_Hold": "On Hold",
"On_Hold": "On hold",
"On_Hold_Chats": "On Hold",
"On_Hold_conversations": "On hold conversations",
"online": "online",
Expand Down Expand Up @@ -3663,6 +3663,7 @@
"Return_to_home": "Return to home",
"Return_to_previous_page": "Return to previous page",
"Return_to_the_queue": "Return back to the Queue",
"Ringing": "Ringing",
"Robot_Instructions_File_Content": "Robots.txt File Contents",
"Default_Referrer_Policy": "Default Referrer Policy",
"Default_Referrer_Policy_Description": "This controls the 'referrer' header that's sent when requesting embedded media from other servers. For more information, refer to <a href='https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy'>this link from MDN</a>. Remember, a full page refresh is required for this to take effect",
Expand Down