Skip to content

Commit

Permalink
feat(plugin-cc): add agent logout
Browse files Browse the repository at this point in the history
  • Loading branch information
rarajes2 committed Oct 30, 2024
1 parent a2a68b9 commit e8da707
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 8 deletions.
15 changes: 15 additions & 0 deletions docs/samples/contact-center/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const agentLogin = document.querySelector('#AgentLogin');
const agentLoginButton = document.querySelector('#loginAgent');
const dialNumber = document.querySelector('#dialNumber');
const registerStatus = document.querySelector('#ws-connection-status');
const logoutAgentElm = document.querySelector('#logoutAgent');

// Store and Grab `access-token` from localstorage
if (localStorage.getItem('date') > new Date().getTime()) {
Expand Down Expand Up @@ -151,12 +152,26 @@ async function handleAgentLogin(e) {
function doAgentLogin() {
webex.cc.stationLogin({teamId: teamsDropdown.value, loginOption: agentDeviceType, dialNumber: dialNumber.value}).then((response) => {
console.log('Agent Logged in successfully', response);
logoutAgentElm.classList.remove('hidden');
}
).catch((error) => {
console.log('Agent Login failed', error);
});
}

function logoutAgent() {
webex.cc.stationLogout({logoutReason: 'logout'}).then((response) => {
console.log('Agent logged out successfully', response);

setTimeout(() => {
logoutAgentElm.classList.add('hidden');
}, 1000);
}
).catch((error) => {
console.log('Agent logout failed', error);
});
}

const allCollapsibleElements = document.querySelectorAll('.collapsible');
allCollapsibleElements.forEach((el) => {
el.addEventListener('click', (event) => {
Expand Down
3 changes: 2 additions & 1 deletion docs/samples/contact-center/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ <h2 class="collapsible">
<div class="u-mv">
<button id="webexcc-register" type="button" onclick="register()" disabled=""
class="btn-code">webex.cc.register()</button>
<p id="ws-connection-status" class="status-par">Not Registered</p>
<p id="ws-connection-status" class="status-par">Not Subscribed</p>
</div>
</fieldset>
</form>
Expand Down Expand Up @@ -112,6 +112,7 @@ <h2 class="collapsible">
<input id="dialNumber" name="dialNumber" placeholder="Dial Number" value="" type="text">
<button id="loginAgent" disabled class="btn btn-primary my-3" onclick="doAgentLogin()">Login With
Selected Team</button>
<button id="logoutAgent" class="btn btn-primary my-3 ml-2 hidden" onclick="logoutAgent()">Logout Agent</button>
</fieldset>
<fieldset>
<legend>Agent status</legend>
Expand Down
24 changes: 23 additions & 1 deletion packages/@webex/plugin-cc/src/cc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {READY, CC_FILE} from './constants';
import Agent from './features/Agent';
import HttpRequest from './services/HttpRequest';
import WebRTCCalling from './WebRTCCalling';
import {StationLoginSuccess} from './services/types';
import {LogoutSuccess, StationLoginSuccess} from './services/types';

export default class ContactCenter extends WebexPlugin implements IContactCenter {
namespace = 'cc';
Expand Down Expand Up @@ -135,4 +135,26 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
return Promise.reject(error);
}
}

/**
* This is used for agent logout.
* @param options
* @returns Promise<LogoutSuccess>
* @throws Error
*/
public async stationLogout(options: {logoutReason: string}): Promise<LogoutSuccess> {
try {
const response = await this.agent.stationLogout(options);

if (this.webRTCCalling) {
this.webRTCCalling.deregisterWebCallingLine();
}

return response;
} catch (error) {
this.$webex.logger.error('LOGOUT API FAILED');

return Promise.reject(new Error('Error while performing agent logout', error.message));
}
}
}
13 changes: 12 additions & 1 deletion packages/@webex/plugin-cc/src/features/Agent.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {STATION_LOGIN_TYPE, WebexSDK} from '../types';
import HttpRequest from '../services/HttpRequest';
import AgentService from '../services/AgentService';
import {StationLoginSuccess} from '../services/types';
import {LogoutSuccess, StationLoginSuccess} from '../services/types';

export default class Agent {
private webex: WebexSDK;
Expand Down Expand Up @@ -34,4 +34,15 @@ export default class Agent {
return Promise.reject(new Error('Error while performing agent login', error));
}
}

public async stationLogout(options: {logoutReason: string}): Promise<LogoutSuccess> {
try {
const response = await this.agentService.stationLogout(options);
this.webex.logger.log('Logout API SUCCESS');

return response;
} catch (error) {
return Promise.reject(error);
}
}
}
37 changes: 35 additions & 2 deletions packages/@webex/plugin-cc/src/services/AgentService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import {STATION_LOGIN_TYPE, WebexSDK, HTTP_METHODS} from '../types';
import {AGENT, LOGIN_API, WCC_API_GATEWAY, WEB_RTC_PREFIX} from './constants';
import {
AGENT,
AgentLogoutFailedEvent,
AgentLogoutSuccessEvent,
LOGIN_API,
LOGOUT_API,
LOGOUT_EVENT,
WCC_API_GATEWAY,
WEB_RTC_PREFIX,
} from './constants';
import HttpRequest from './HttpRequest';
import {StationLoginSuccess} from './types';
import {LogoutSuccess, StationLoginSuccess} from './types';

export default class AgentService {
private webex: WebexSDK;
Expand Down Expand Up @@ -56,4 +65,28 @@ export default class AgentService {
return Promise.reject(error);
}
}

public async stationLogout(options: {logoutReason: string}): Promise<LogoutSuccess> {
try {
const {logoutReason} = options;
const payload = {
logoutReason,
};
const data = await this.httpRequest.sendRequestWithEvent({
service: WCC_API_GATEWAY,
resource: LOGOUT_API,
method: HTTP_METHODS.PUT,
payload,
eventType: LOGOUT_EVENT,
success: [AgentLogoutSuccessEvent],
failure: [AgentLogoutFailedEvent],
});

return data;
} catch (error) {
this.webex.logger.error(`Error during station logout: ${error}`);

return Promise.reject(error);
}
}
}
7 changes: 7 additions & 0 deletions packages/@webex/plugin-cc/src/services/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,11 @@ export const AGENT = 'agent';
// CC GATEWAY API URL PATHS
export const SUBSCRIBE_API = 'v1/notification/subscribe';
export const LOGIN_API = 'v1/agents/login';
export const LOGOUT_API = 'v1/agents/logout';
export const WEB_RTC_PREFIX = 'webrtc-';

export const AgentDesktopMessage = 'AgentDesktopMessage';

export const LOGOUT_EVENT = 'Logout';
export const AgentLogoutSuccessEvent = 'AgentLogoutSuccess';
export const AgentLogoutFailedEvent = 'AgentLogoutFailed';
17 changes: 15 additions & 2 deletions packages/@webex/plugin-cc/src/services/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {AgentDesktopMessage, AgentLogoutSuccessEvent} from './constants';

type Enum<T extends Record<string, unknown>> = T[keyof T];

export type Msg<T = any> = {
Expand Down Expand Up @@ -188,7 +190,6 @@ export interface Team {
* Represents AuxCode.
* @public
*/

export interface AuxCode {
/**
* ID of the Auxiliary Code.
Expand Down Expand Up @@ -232,7 +233,19 @@ export interface AuxCode {
*
* @public
*/

export interface ListAuxCodesResponse {
data: AuxCode[];
}

export interface LogoutSuccess {
eventType: typeof AgentDesktopMessage;
agentId: string;
trackingId: string;
agentSessionId: string;
orgId: string;
status: string;
subStatus: string;
loggedOutBy?: string;
roles?: string[];
type: typeof AgentLogoutSuccessEvent;
}
27 changes: 26 additions & 1 deletion packages/@webex/plugin-cc/test/unit/spec/features/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,29 @@ describe('Agent', () => {
expect(webexMock.logger.log).toHaveBeenCalledWith('LOGIN API SUCCESS');
expect(response).toBe(loginResponse);
});
});

describe('#stationLogout', () => {
it('should successfully log out the agent', async () => {
const options = { logoutReason: 'End of shift' };

const logoutResponse = { success: true };
agentServiceMock.stationLogout.mockResolvedValue(logoutResponse);

const result = await agent.stationLogout(options);

expect(result).toBe(logoutResponse);
expect(agentServiceMock.stationLogout).toHaveBeenCalledWith(options);
expect(webex.logger.log).toHaveBeenCalledWith('Logout API SUCCESS');
});

it('should handle logout error', async () => {
const options = { logoutReason: 'End of shift' };

const error = new Error('Logout failed');
agentServiceMock.stationLogout.mockRejectedValue(error);

await expect(agent.stationLogout(options)).rejects.toThrow('Error while performing agent Logout');
expect(agentServiceMock.stationLogout).toHaveBeenCalledWith(options);
});
});
});

0 comments on commit e8da707

Please sign in to comment.