Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cc-sdk): added-device-type-for-agent-config #4006

Merged
merged 5 commits into from
Nov 27, 2024
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
6 changes: 4 additions & 2 deletions docs/samples/contact-center/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,15 @@ function register() {
});
const loginVoiceOptions = agentProfile.loginVoiceOptions;
agentLogin.innerHTML = '<option value="" selected>Choose Agent Login ...</option>'; // Clear previously selected option on agentLogin.
dialNumber.value = '';
dialNumber.disabled = true;
dialNumber.value = agentProfile.defaultDn ? agentProfile.defaultDn : '';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, we simply update the dial number if it exists (ie for EXTENSION and AGENT_DN relogin case).
Note that we disable it if the defaultDn is undefined.

I personally felt this approach was better (ie using the defaultDn of the agent config), however if there are some issues here, I am open to changing.

dialNumber.disabled = agentProfile.defaultDn ? false : true;
if(loginVoiceOptions.length > 0) agentLoginButton.disabled = false;
loginVoiceOptions.forEach((voiceOptions)=> {
const option = document.createElement('option');
option.text = voiceOptions;
option.value = voiceOptions;
agentLogin.add(option);
option.selected = agentProfile.isAgentLoggedIn && voiceOptions === agentProfile.deviceType;
});

if (agentProfile.isAgentLoggedIn) {
Expand Down Expand Up @@ -207,6 +208,7 @@ function logoutAgent() {

setTimeout(() => {
logoutAgentElm.classList.add('hidden');
agentLogin.selectedIndex = 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed in order tor reset the login dropdown status as in the register we set one of the options, if the agent is already logged.

}, 1000);
}
).catch((error) => {
Expand Down
27 changes: 25 additions & 2 deletions packages/@webex/plugin-cc/src/cc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
private async silentRelogin(): Promise<void> {
try {
const reLoginResponse = await this.services.agent.reload();
const {auxCodeId, agentId, lastStateChangeReason} = reLoginResponse.data;
const {auxCodeId, agentId, lastStateChangeReason, deviceType, dn} = reLoginResponse.data;

if (lastStateChangeReason === 'agent-wss-disconnect') {
LoggerProxy.info(
Expand All @@ -310,7 +310,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
};
await this.setAgentState(stateChangeData);
}
// Updating isAgentLoggedIn as true to indicate to the end user

await this.handleDeviceType(deviceType as LoginOption, dn);
this.agentConfig.isAgentLoggedIn = true;
} catch (error) {
const {reason, error: detailedError} = getErrorDetails(error, 'silentReLogin', CC_FILE);
Expand All @@ -325,4 +326,26 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
throw detailedError;
}
}

/**
* Handles the device type specific logic
*/
private async handleDeviceType(deviceType: LoginOption, dn: string): Promise<void> {
switch (deviceType) {
case LoginOption.BROWSER:
await this.webCallingService.registerWebCallingLine();
break;
case LoginOption.AGENT_DN:
case LoginOption.EXTENSION:
this.agentConfig.defaultDn = dn;
break;
default:
LoggerProxy.error(`Unsupported device type: ${deviceType}`, {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should ideally never reach here, however we must account for all possibilites.

module: CC_FILE,
method: this.handleDeviceType.name,
});
throw new Error(`Unsupported device type: ${deviceType}`);
}
this.agentConfig.deviceType = deviceType;
}
}
65 changes: 65 additions & 0 deletions packages/@webex/plugin-cc/test/unit/spec/cc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ describe('webex.cc', () => {
data: {
auxCodeId: 'auxCodeId',
agentId: 'agentId',
deviceType: LoginOption.EXTENSION,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to mock this so we do not see any errors.

dn: '12345',
},
});
const configSpy = jest
Expand Down Expand Up @@ -667,6 +669,8 @@ describe('webex.cc', () => {
auxCodeId: 'auxCodeId',
agentId: 'agentId',
lastStateChangeReason: 'agent-wss-disconnect',
deviceType: LoginOption.BROWSER,
dn: '12345',
},
};

Expand Down Expand Up @@ -695,6 +699,7 @@ describe('webex.cc', () => {
agentId: 'agentId',
});
expect(webex.cc.agentConfig.isAgentLoggedIn).toBe(true);
expect(webex.cc.agentConfig.deviceType).toBe(LoginOption.BROWSER);
});

it('should handle AGENT_NOT_FOUND error silently', async () => {
Expand All @@ -714,5 +719,65 @@ describe('webex.cc', () => {
{module: CC_FILE, method: 'silentRelogin'}
);
});

it('should handle errors during silent relogin', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added few more tests so coverage is improved.

const error = new Error('Error while performing silentReLogin');
jest.spyOn(webex.cc.services.agent, 'reload').mockRejectedValue(error);

await expect(webex.cc['silentRelogin']()).rejects.toThrow(error);
});

it('should update agentConfig with deviceType during silent relogin for EXTENSION', async () => {
const mockReLoginResponse = {
data: {
auxCodeId: 'auxCodeId',
agentId: 'agentId',
lastStateChangeReason: 'agent-wss-disconnect',
deviceType: LoginOption.EXTENSION,
dn: '12345',
},
};

// Mock the agentConfig
webex.cc.agentConfig = {
agentId: 'agentId',
agentProfileID: 'test-agent-profile-id',
isAgentLoggedIn: false,
} as Profile;

jest.spyOn(webex.cc.services.agent, 'reload').mockResolvedValue(mockReLoginResponse);

await webex.cc['silentRelogin']();

expect(webex.cc.agentConfig.deviceType).toBe(LoginOption.EXTENSION);
expect(webex.cc.agentConfig.defaultDn).toBe('12345');
});

it('should update agentConfig with deviceType during silent relogin for AGENT_DN', async () => {
const mockReLoginResponse = {
data: {
auxCodeId: 'auxCodeId',
agentId: 'agentId',
lastStateChangeReason: 'agent-wss-disconnect',
deviceType: LoginOption.AGENT_DN,
dn: '67890',
subStatus: 'subStatusValue',
},
};

// Mock the agentConfig
webex.cc.agentConfig = {
agentId: 'agentId',
agentProfileID: 'test-agent-profile-id',
isAgentLoggedIn: false,
} as Profile;

jest.spyOn(webex.cc.services.agent, 'reload').mockResolvedValue(mockReLoginResponse);

await webex.cc['silentRelogin']();

expect(webex.cc.agentConfig.deviceType).toBe(LoginOption.AGENT_DN);
expect(webex.cc.agentConfig.defaultDn).toBe('67890');
});
});
});