Skip to content

Commit

Permalink
fix(user-state): receive agent stateChange event (#350)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkesavan13 authored Dec 23, 2024
1 parent 31ebfb1 commit 21d6ce7
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 16 deletions.
2 changes: 1 addition & 1 deletion packages/contact-center/store/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"react": "18.3.1",
"react-dom": "18.3.1",
"typescript": "5.6.3",
"webex": "3.6.0-wxcc.5"
"webex": "3.7.0-wxcc.3"
},
"devDependencies": {
"@babel/core": "7.25.2",
Expand Down
1 change: 1 addition & 0 deletions packages/contact-center/user-state/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const AGENT_STATE_CHANGE = 'agent:stateChange';
22 changes: 20 additions & 2 deletions packages/contact-center/user-state/src/helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {useState, useEffect} from "react";
// TODO: Export & Import this AGENT_STATE_CHANGE constant from SDK
import {AGENT_STATE_CHANGE} from './constants';

export const useUserState = ({idleCodes, agentId, cc}) => {

Expand All @@ -11,12 +13,28 @@ export const useUserState = ({idleCodes, agentId, cc}) => {
useEffect(() => {
// Reset the timer whenever the component mounts or the state changes
setElapsedTime(0);
const timer = setInterval(() => {
let timer = setInterval(() => {
setElapsedTime(prevTime => prevTime + 1);
}, 1000);

const handleStateChange = (data) => {
if (data && typeof data === 'object' && data.type === 'AgentStateChangeSuccess') {
const DEFAULT_CODE = '0'; // Default code when no aux code is present
setCurrentState({
id: data.auxCodeId?.trim() !== '' ? data.auxCodeId : DEFAULT_CODE
});
setElapsedTime(0);
}
};

cc.on(AGENT_STATE_CHANGE, handleStateChange);

// Cleanup the timer on component unmount
return () => clearInterval(timer);
return () => {
clearInterval(timer);
timer = null;
cc.off(AGENT_STATE_CHANGE, handleStateChange);
}
}, []);

const setAgentStatus = (selectedCode) => {
Expand Down
62 changes: 61 additions & 1 deletion packages/contact-center/user-state/tests/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { useUserState } from '../src/helper';

describe('useUserState Hook', () => {
const mockCC = {
setAgentState: jest.fn()
setAgentState: jest.fn(),
on: jest.fn(),
off: jest.fn(),
};

const idleCodes = [
Expand All @@ -16,6 +18,8 @@ describe('useUserState Hook', () => {
beforeEach(() => {
jest.useFakeTimers();
mockCC.setAgentState.mockReset();
mockCC.on.mockReset();
mockCC.off.mockReset();
});

afterEach(() => {
Expand All @@ -31,6 +35,9 @@ describe('useUserState Hook', () => {
elapsedTime: 0,
currentState: {}
});

expect(mockCC.on).toHaveBeenCalledTimes(1);
expect(mockCC.on).toHaveBeenCalledWith('agent:stateChange', expect.any(Function));
});

it('should increment elapsedTime every second', () => {
Expand Down Expand Up @@ -93,4 +100,57 @@ describe('useUserState Hook', () => {
});
});
});

it('should handle agent state change events correctly', async () => {
const { result } = renderHook(() => useUserState({ idleCodes, agentId, cc: mockCC }));

// Get the handler function that was registered
const handler = mockCC.on.mock.calls[0][1];

// Test with right event type
act(() => {
handler({ type: 'AgentStateChangeSuccess', auxCodeId: '123' });
});

await waitFor(() => {
expect(result.current.currentState).toEqual({ id: '123' });
});

// Test with wrong event type
act(() => {
handler({ type: 'WrongType' });
});

await waitFor(() => {
expect(result.current.currentState).toEqual({ id: '123' });
});

// Test again with right event type but different value
act(() => {
handler({ type: 'AgentStateChangeSuccess', auxCodeId: '1213' });
});

await waitFor(() => {
expect(result.current.currentState).toEqual({ id: '1213' });
});

// Test with empty auxCodeId
act(() => {
handler({ type: 'AgentStateChangeSuccess', auxCodeId: '' });
});

await waitFor(() => {
expect(result.current.currentState).toEqual({ id: '0' });
});
});

it('should cleanup event listener on unmount', () => {
const { unmount } = renderHook(() => useUserState({ idleCodes, agentId, cc: mockCC }));

unmount();

// Verify that off was called with the same event and handler
expect(mockCC.off).toHaveBeenCalledTimes(1);
expect(mockCC.off).toHaveBeenCalledWith('agent:stateChange', expect.any(Function));
});
});
11 changes: 9 additions & 2 deletions packages/contact-center/user-state/tests/user-state/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import '@testing-library/jest-dom';

// Mock the store import
jest.mock('@webex/cc-store', () => {return {
cc: {},
cc: {
on: jest.fn(),
off: jest.fn(),
},
idleCodes: [],
agentId: 'testAgentId'
}});
Expand All @@ -17,7 +20,11 @@ describe('UserState Component', () => {

render(<UserState/>);

expect(useUserStateSpy).toHaveBeenCalledWith({cc: {}, idleCodes: [], agentId: 'testAgentId'});
expect(useUserStateSpy).toHaveBeenCalledTimes(1);
expect(useUserStateSpy).toHaveBeenCalledWith({cc: {
on: expect.any(Function),
off: expect.any(Function)
}, idleCodes: [], agentId: 'testAgentId'});
const heading = screen.getByTestId('user-state-title');
expect(heading).toHaveTextContent('Agent State');
});
Expand Down
20 changes: 10 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5435,7 +5435,7 @@ __metadata:
react-dom: "npm:18.3.1"
ts-loader: "npm:9.5.1"
typescript: "npm:5.6.3"
webex: "npm:3.6.0-wxcc.5"
webex: "npm:3.7.0-wxcc.3"
webpack: "npm:5.94.0"
webpack-cli: "npm:5.1.4"
webpack-merge: "npm:6.0.1"
Expand Down Expand Up @@ -6382,17 +6382,17 @@ __metadata:
languageName: node
linkType: hard

"@webex/plugin-cc@npm:3.5.0-wxcc.4":
version: 3.5.0-wxcc.4
resolution: "@webex/plugin-cc@npm:3.5.0-wxcc.4"
"@webex/plugin-cc@npm:3.5.0-wxcc.9":
version: 3.5.0-wxcc.9
resolution: "@webex/plugin-cc@npm:3.5.0-wxcc.9"
dependencies:
"@types/platform": "npm:1.3.4"
"@webex/calling": "npm:3.6.0-wxcc.1"
"@webex/internal-plugin-mercury": "npm:3.5.0-wxcc.1"
"@webex/webex-core": "npm:3.5.0-wxcc.1"
buffer: "npm:6.0.3"
jest-html-reporters: "npm:3.0.11"
checksum: 10c0/bc4f04c3c827cf0edb9b4d5fc435fa5e7dee77d8e2b42d31cc86d17cfd35df3601584309feb3f6515916989bbc2304530c69c257dd4c84b05495a272bf92efbb
checksum: 10c0/238585455185112cbe13460a4477a71346c1a33a1b083704eb45b3ed737a6001f8dd221c8914160adc42482bcbdfdbd53fed9ec5a81d83a354e6e9efd573f786
languageName: node
linkType: hard

Expand Down Expand Up @@ -25907,9 +25907,9 @@ __metadata:
languageName: node
linkType: hard

"webex@npm:3.6.0-wxcc.5":
version: 3.6.0-wxcc.5
resolution: "webex@npm:3.6.0-wxcc.5"
"webex@npm:3.7.0-wxcc.3":
version: 3.7.0-wxcc.3
resolution: "webex@npm:3.7.0-wxcc.3"
dependencies:
"@babel/polyfill": "npm:^7.12.1"
"@babel/runtime-corejs2": "npm:^7.14.8"
Expand All @@ -25923,7 +25923,7 @@ __metadata:
"@webex/internal-plugin-voicea": "npm:3.5.0-wxcc.1"
"@webex/plugin-attachment-actions": "npm:3.5.0-wxcc.1"
"@webex/plugin-authorization": "npm:3.5.0-wxcc.1"
"@webex/plugin-cc": "npm:3.5.0-wxcc.4"
"@webex/plugin-cc": "npm:3.5.0-wxcc.9"
"@webex/plugin-device-manager": "npm:3.5.0-wxcc.1"
"@webex/plugin-logger": "npm:3.5.0-wxcc.1"
"@webex/plugin-meetings": "npm:3.5.0-wxcc.1"
Expand All @@ -25937,7 +25937,7 @@ __metadata:
"@webex/storage-adapter-local-storage": "npm:3.5.0-wxcc.1"
"@webex/webex-core": "npm:3.5.0-wxcc.1"
lodash: "npm:^4.17.21"
checksum: 10c0/2268058f35abae6cccdfb994dd04a041b8c646bad8dc75b2eb56f00ed2c39019be2b506f1fe4cbcbe0c9d308c0483e7f157e7280f840b2e6c5155f4c9f27afe3
checksum: 10c0/ee83226f0d884db685b86fadf514c2cddfcbf91f8329d691be4132828e29477a6551bfebfe82a510b24b223319d0eb6badb7322d10713fec1c302a879a253e9d
languageName: node
linkType: hard

Expand Down

0 comments on commit 21d6ce7

Please sign in to comment.