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: 11 additions & 6 deletions packages/contact-center/station-login/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const useStationLogin = (props: UseStationLoginProps) => {
const cc = props.cc;
const loginCb = props.onLogin;
const logoutCb = props.onLogout;
const logger = props.logger;
const [dialNumber, setDialNumber] = useState('');
const [deviceType, setDeviceType] = useState('');
const [team, setTeam] = useState('');
Expand All @@ -22,9 +23,11 @@ export const useStationLogin = (props: UseStationLoginProps) => {
if (loginCb) {
loginCb();
}
})
.catch((error: Error) => {
console.error(error);
}).catch((error: Error) => {
logger.error(`Error logging in: ${error}`, {
module: 'widget-station-login#helper.ts',
method: 'login',
});
setLoginFailure(error);
});
};
Expand All @@ -36,9 +39,11 @@ export const useStationLogin = (props: UseStationLoginProps) => {
if (logoutCb) {
logoutCb();
}
})
.catch((error: Error) => {
console.error(error);
}).catch((error: Error) => {
logger.error(`Error logging out: ${error}`, {
module: 'widget-station-login#helper.ts',
method: 'logout',
});
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {useStationLogin} from '../helper';
import {StationLoginProps} from './station-login.types';

const StationLogin: React.FunctionComponent<StationLoginProps> = observer(({onLogin, onLogout}) => {
const {cc, teams, loginOptions} = store;
const result = useStationLogin({cc, onLogin, onLogout});
const {cc, teams, loginOptions, logger} = store;
const result = useStationLogin({cc, onLogin, onLogout, logger});

const props = {
...result,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {AgentLogin, IContactCenter, StationLoginSuccess, StationLogoutSuccess, Team} from '@webex/plugin-cc';
import {ILogger} from '@webex/cc-store';
/**
* Interface representing the properties for the Station Login component.
*/
Expand Down Expand Up @@ -72,6 +73,11 @@ export interface IStationLoginProps {
* Handler to set the selected agent team
*/
setTeam: (team: string) => void;

/**
* The logger instance from SDK
*/
logger: ILogger;
}

export type StationLoginPresentationalProps = Pick<
Expand All @@ -89,6 +95,6 @@ export type StationLoginPresentationalProps = Pick<
| 'setTeam'
>;

export type UseStationLoginProps = Pick<IStationLoginProps, 'cc' | 'onLogin' | 'onLogout'>;
export type UseStationLoginProps = Pick<IStationLoginProps, 'cc' | 'onLogin' | 'onLogout' | 'logger'>;

export type StationLoginProps = Pick<IStationLoginProps, 'onLogin' | 'onLogout'>;
99 changes: 67 additions & 32 deletions packages/contact-center/station-login/tests/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@ const loginParams = {

const loginCb = jest.fn();
const logoutCb = jest.fn();
const logger = {
error: jest.fn()
};

describe('useStationLogin Hook', () => {
afterEach(() => {
jest.clearAllMocks();
loginCb.mockClear();
logoutCb.mockClear();
logger.error.mockClear();
});

it('should set loginSuccess on successful login', async () => {
Expand Down Expand Up @@ -61,17 +67,19 @@ describe('useStationLogin Hook', () => {
ccMock.stationLogin.mockResolvedValue(successResponse);
const setSelectedLoginOptionSpy = jest.spyOn(require('@webex/cc-store'), 'setSelectedLoginOption');

const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb}));

result.current.setDeviceType(loginParams.loginOption);
result.current.setDialNumber(loginParams.dialNumber);
result.current.setTeam(loginParams.teamId);
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger}));

act(() => {
result.current.login();
result.current.setDeviceType(loginParams.loginOption);
result.current.setDialNumber(loginParams.dialNumber);
result.current.setTeam(loginParams.teamId);
});

await act(async () => {
await result.current.login();
});

waitFor(() => {
await waitFor(async () => {
expect(ccMock.stationLogin).toHaveBeenCalledWith({
teamId: loginParams.teamId,
loginOption: loginParams.loginOption,
Expand Down Expand Up @@ -100,17 +108,20 @@ describe('useStationLogin Hook', () => {
ccMock.stationLogin.mockRejectedValue(errorResponse);
const setSelectedLoginOptionSpy = jest.spyOn(require('@webex/cc-store'), 'setSelectedLoginOption');

const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb}));

result.current.setDeviceType(loginParams.loginOption);
result.current.setDialNumber(loginParams.dialNumber);
result.current.setTeam(loginParams.teamId);
loginCb.mockClear();
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger}));

act(() => {
result.current.login();
result.current.setDeviceType(loginParams.loginOption);
result.current.setDialNumber(loginParams.dialNumber);
result.current.setTeam(loginParams.teamId);
});

await act(async () => {
await result.current.login();
});

waitFor(() => {
await waitFor(() => {
expect(ccMock.stationLogin).toHaveBeenCalledWith({
teamId: loginParams.teamId,
loginOption: loginParams.loginOption,
Expand All @@ -135,15 +146,18 @@ describe('useStationLogin Hook', () => {
});

it('should not call login callback if not present', async () => {

ccMock.stationLogin.mockResolvedValue({});

const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogout: logoutCb}));
const { result } = renderHook(() =>
useStationLogin({cc: ccMock, onLogout: logoutCb, logger})
);

act(() => {
result.current.login();
await act(async () => {
await result.current.login();
});

waitFor(() => {
await waitFor(() => {
expect(loginCb).not.toHaveBeenCalled();
});
});
Expand All @@ -153,14 +167,16 @@ describe('useStationLogin Hook', () => {
ccMock.stationLogin.mockRejectedValue(errorResponse);

loginCb.mockClear();
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb}));

result.current.setDeviceType(loginParams.loginOption);
result.current.setDialNumber(loginParams.dialNumber);
result.current.setTeam(loginParams.teamId);
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger}));

act(() => {
result.current.login();
result.current.setDeviceType(loginParams.loginOption);
result.current.setDialNumber(loginParams.dialNumber);
result.current.setTeam(loginParams.teamId);
});

await act(async () => {
await result.current.login();
});

waitFor(() => {
Expand Down Expand Up @@ -204,13 +220,13 @@ describe('useStationLogin Hook', () => {

ccMock.stationLogout.mockResolvedValue(successResponse);

const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb}));
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger}));

act(() => {
result.current.logout();
await act(async () => {
await result.current.logout();
});

waitFor(() => {
await waitFor(() => {
expect(ccMock.stationLogout).toHaveBeenCalledWith({logoutReason: 'User requested logout'});
expect(logoutCb).toHaveBeenCalledWith();

Expand All @@ -228,16 +244,35 @@ describe('useStationLogin Hook', () => {
});
});

it('should log error on logout failure', async () => {
ccMock.stationLogout.mockRejectedValue(new Error('Logout failed'));

const {result} = renderHook(() =>
useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger})
);

await act(async () => {
await result.current.logout();
});

await waitFor(() => {
expect(logger.error).toHaveBeenCalledWith('Error logging out: Error: Logout failed', {
module: 'widget-station-login#helper.ts',
method: 'logout',
});
});
});

it('should not call logout callback if not present', async () => {
ccMock.stationLogout.mockResolvedValue({});

const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb}));
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, logger}));

act(() => {
result.current.logout();
await act(async () => {
await result.current.logout();
});

waitFor(() => {
await waitFor(() => {
expect(logoutCb).not.toHaveBeenCalled();
});
});
Expand Down
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 @@
"dependencies": {
"mobx": "6.13.5",
"typescript": "5.6.3",
"webex": "3.7.0-wxcc.5"
"webex": "3.7.0-wxcc.6"
},
"devDependencies": {
"@babel/core": "7.25.2",
Expand Down
35 changes: 23 additions & 12 deletions packages/contact-center/store/src/store.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import {makeAutoObservable, observable} from 'mobx';
import Webex from 'webex';
import {IContactCenter, Profile, Team, WithWebex, IdleCode, InitParams, IStore} from './store.types';
import {
IContactCenter,
Profile,
Team,
WithWebex,
IdleCode,
InitParams,
IStore,
ILogger
} from './store.types';

class Store implements IStore {
private static instance: Store;
teams: Team[] = [];
loginOptions: string[] = [];
cc: IContactCenter;
logger: ILogger;
idleCodes: IdleCode[] = [];
agentId: string = '';
selectedLoginOption: string = '';
Expand All @@ -31,18 +41,19 @@ class Store implements IStore {

registerCC(webex: WithWebex['webex']): Promise<void> {
this.cc = webex.cc;
return this.cc
.register()
.then((response: Profile) => {
this.teams = response.teams;
this.loginOptions = response.loginVoiceOptions;
this.idleCodes = response.idleCodes;
this.agentId = response.agentId;
})
.catch((error) => {
console.error('Error registering contact center', error);
return Promise.reject(error);
this.logger = this.cc.LoggerProxy;
return this.cc.register().then((response: Profile) => {
this.teams = response.teams;
this.loginOptions = response.loginVoiceOptions;
this.idleCodes = response.idleCodes;
this.agentId = response.agentId;
}).catch((error) => {
this.logger.error(`Error registering contact center: ${error}`, {
module: 'cc-store#store.ts',
method: 'registerCC',
});
return Promise.reject(error);
});
}

init(options: InitParams): Promise<void> {
Expand Down
20 changes: 15 additions & 5 deletions packages/contact-center/store/src/store.types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import {AgentLogin, IContactCenter, Profile, Team} from '@webex/plugin-cc';
import {AgentLogin, IContactCenter, Profile, Team, LogContext} from '@webex/plugin-cc';

type ILogger = {
log: (message: string, context?: LogContext) => void;
info: (message: string, context?: LogContext) => void;
warn: (message: string, context?: LogContext) => void;
trace: (message: string, context?: LogContext) => void;
error: (message: string, context?: LogContext) => void;
}

interface WithWebex {
webex: { cc: IContactCenter };
webex: { cc: IContactCenter, logger: ILogger };
}

interface WithWebexConfig {
Expand All @@ -24,11 +32,12 @@ interface IStore {
cc: IContactCenter;
idleCodes: IdleCode[];
agentId: string;

logger: ILogger;
registerCC(webex: WithWebex['webex']): Promise<Profile>;
init(params: InitParams): Promise<void>;
}


export type {
IContactCenter,
Profile,
Expand All @@ -37,5 +46,6 @@ export type {
WithWebex,
IdleCode,
InitParams,
IStore
}
IStore,
ILogger,
}
12 changes: 8 additions & 4 deletions packages/contact-center/store/tests/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ jest.mock('webex', () => ({
}
}),
cc: {
register: jest.fn()
register: jest.fn(),
LoggerProxy: {
error: jest.fn()
}
}
}))
}));
Expand Down Expand Up @@ -62,7 +65,6 @@ describe('Store', () => {
});

it('should log an error on failed register', async () => {
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
const mockError = new Error('Register failed');
mockWebex.cc.register.mockRejectedValue(mockError);

Expand All @@ -71,8 +73,10 @@ describe('Store', () => {
}
catch (error) {
expect(error).toEqual(mockError);
expect(consoleErrorSpy).toHaveBeenCalledWith('Error registering contact center', mockError);
consoleErrorSpy.mockRestore();
expect(store.logger.error).toHaveBeenCalledWith("Error registering contact center: Error: Register failed", {
"method": "registerCC",
"module": "cc-store#store.ts",
});
}
});
});
Expand Down
Loading