Skip to content

Commit a62494b

Browse files
authored
feat(cc-store): add logger from sdk (webex#354)
1 parent ff71785 commit a62494b

File tree

15 files changed

+2015
-1289
lines changed

15 files changed

+2015
-1289
lines changed

packages/contact-center/station-login/src/helper.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const useStationLogin = (props: UseStationLoginProps) => {
77
const cc = props.cc;
88
const loginCb = props.onLogin;
99
const logoutCb = props.onLogout;
10+
const logger = props.logger;
1011
const [dialNumber, setDialNumber] = useState('');
1112
const [deviceType, setDeviceType] = useState('');
1213
const [team, setTeam] = useState('');
@@ -22,9 +23,11 @@ export const useStationLogin = (props: UseStationLoginProps) => {
2223
if (loginCb) {
2324
loginCb();
2425
}
25-
})
26-
.catch((error: Error) => {
27-
console.error(error);
26+
}).catch((error: Error) => {
27+
logger.error(`Error logging in: ${error}`, {
28+
module: 'widget-station-login#helper.ts',
29+
method: 'login',
30+
});
2831
setLoginFailure(error);
2932
});
3033
};
@@ -36,9 +39,11 @@ export const useStationLogin = (props: UseStationLoginProps) => {
3639
if (logoutCb) {
3740
logoutCb();
3841
}
39-
})
40-
.catch((error: Error) => {
41-
console.error(error);
42+
}).catch((error: Error) => {
43+
logger.error(`Error logging out: ${error}`, {
44+
module: 'widget-station-login#helper.ts',
45+
method: 'logout',
46+
});
4247
});
4348
};
4449

packages/contact-center/station-login/src/station-login/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {useStationLogin} from '../helper';
77
import {StationLoginProps} from './station-login.types';
88

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

1313
const props = {
1414
...result,

packages/contact-center/station-login/src/station-login/station-login.types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {AgentLogin, IContactCenter, StationLoginSuccess, StationLogoutSuccess, Team} from '@webex/plugin-cc';
2+
import {ILogger} from '@webex/cc-store';
23
/**
34
* Interface representing the properties for the Station Login component.
45
*/
@@ -72,6 +73,11 @@ export interface IStationLoginProps {
7273
* Handler to set the selected agent team
7374
*/
7475
setTeam: (team: string) => void;
76+
77+
/**
78+
* The logger instance from SDK
79+
*/
80+
logger: ILogger;
7581
}
7682

7783
export type StationLoginPresentationalProps = Pick<
@@ -89,6 +95,6 @@ export type StationLoginPresentationalProps = Pick<
8995
| 'setTeam'
9096
>;
9197

92-
export type UseStationLoginProps = Pick<IStationLoginProps, 'cc' | 'onLogin' | 'onLogout'>;
98+
export type UseStationLoginProps = Pick<IStationLoginProps, 'cc' | 'onLogin' | 'onLogout' | 'logger'>;
9399

94100
export type StationLoginProps = Pick<IStationLoginProps, 'onLogin' | 'onLogout'>;

packages/contact-center/station-login/tests/helper.ts

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,16 @@ const loginParams = {
2828

2929
const loginCb = jest.fn();
3030
const logoutCb = jest.fn();
31+
const logger = {
32+
error: jest.fn()
33+
};
3134

3235
describe('useStationLogin Hook', () => {
3336
afterEach(() => {
3437
jest.clearAllMocks();
38+
loginCb.mockClear();
39+
logoutCb.mockClear();
40+
logger.error.mockClear();
3541
});
3642

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

64-
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb}));
65-
66-
result.current.setDeviceType(loginParams.loginOption);
67-
result.current.setDialNumber(loginParams.dialNumber);
68-
result.current.setTeam(loginParams.teamId);
70+
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger}));
6971

7072
act(() => {
71-
result.current.login();
73+
result.current.setDeviceType(loginParams.loginOption);
74+
result.current.setDialNumber(loginParams.dialNumber);
75+
result.current.setTeam(loginParams.teamId);
76+
});
77+
78+
await act(async () => {
79+
await result.current.login();
7280
});
7381

74-
waitFor(() => {
82+
await waitFor(async () => {
7583
expect(ccMock.stationLogin).toHaveBeenCalledWith({
7684
teamId: loginParams.teamId,
7785
loginOption: loginParams.loginOption,
@@ -100,17 +108,20 @@ describe('useStationLogin Hook', () => {
100108
ccMock.stationLogin.mockRejectedValue(errorResponse);
101109
const setSelectedLoginOptionSpy = jest.spyOn(require('@webex/cc-store'), 'setSelectedLoginOption');
102110

103-
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb}));
104-
105-
result.current.setDeviceType(loginParams.loginOption);
106-
result.current.setDialNumber(loginParams.dialNumber);
107-
result.current.setTeam(loginParams.teamId);
111+
loginCb.mockClear();
112+
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger}));
108113

109114
act(() => {
110-
result.current.login();
115+
result.current.setDeviceType(loginParams.loginOption);
116+
result.current.setDialNumber(loginParams.dialNumber);
117+
result.current.setTeam(loginParams.teamId);
118+
});
119+
120+
await act(async () => {
121+
await result.current.login();
111122
});
112123

113-
waitFor(() => {
124+
await waitFor(() => {
114125
expect(ccMock.stationLogin).toHaveBeenCalledWith({
115126
teamId: loginParams.teamId,
116127
loginOption: loginParams.loginOption,
@@ -135,15 +146,18 @@ describe('useStationLogin Hook', () => {
135146
});
136147

137148
it('should not call login callback if not present', async () => {
149+
138150
ccMock.stationLogin.mockResolvedValue({});
139151

140-
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogout: logoutCb}));
152+
const { result } = renderHook(() =>
153+
useStationLogin({cc: ccMock, onLogout: logoutCb, logger})
154+
);
141155

142-
act(() => {
143-
result.current.login();
156+
await act(async () => {
157+
await result.current.login();
144158
});
145159

146-
waitFor(() => {
160+
await waitFor(() => {
147161
expect(loginCb).not.toHaveBeenCalled();
148162
});
149163
});
@@ -153,14 +167,16 @@ describe('useStationLogin Hook', () => {
153167
ccMock.stationLogin.mockRejectedValue(errorResponse);
154168

155169
loginCb.mockClear();
156-
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb}));
157-
158-
result.current.setDeviceType(loginParams.loginOption);
159-
result.current.setDialNumber(loginParams.dialNumber);
160-
result.current.setTeam(loginParams.teamId);
170+
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger}));
161171

162172
act(() => {
163-
result.current.login();
173+
result.current.setDeviceType(loginParams.loginOption);
174+
result.current.setDialNumber(loginParams.dialNumber);
175+
result.current.setTeam(loginParams.teamId);
176+
});
177+
178+
await act(async () => {
179+
await result.current.login();
164180
});
165181

166182
waitFor(() => {
@@ -204,13 +220,13 @@ describe('useStationLogin Hook', () => {
204220

205221
ccMock.stationLogout.mockResolvedValue(successResponse);
206222

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

209-
act(() => {
210-
result.current.logout();
225+
await act(async () => {
226+
await result.current.logout();
211227
});
212228

213-
waitFor(() => {
229+
await waitFor(() => {
214230
expect(ccMock.stationLogout).toHaveBeenCalledWith({logoutReason: 'User requested logout'});
215231
expect(logoutCb).toHaveBeenCalledWith();
216232

@@ -228,16 +244,35 @@ describe('useStationLogin Hook', () => {
228244
});
229245
});
230246

247+
it('should log error on logout failure', async () => {
248+
ccMock.stationLogout.mockRejectedValue(new Error('Logout failed'));
249+
250+
const {result} = renderHook(() =>
251+
useStationLogin({cc: ccMock, onLogin: loginCb, onLogout: logoutCb, logger})
252+
);
253+
254+
await act(async () => {
255+
await result.current.logout();
256+
});
257+
258+
await waitFor(() => {
259+
expect(logger.error).toHaveBeenCalledWith('Error logging out: Error: Logout failed', {
260+
module: 'widget-station-login#helper.ts',
261+
method: 'logout',
262+
});
263+
});
264+
});
265+
231266
it('should not call logout callback if not present', async () => {
232267
ccMock.stationLogout.mockResolvedValue({});
233268

234-
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb}));
269+
const {result} = renderHook(() => useStationLogin({cc: ccMock, onLogin: loginCb, logger}));
235270

236-
act(() => {
237-
result.current.logout();
271+
await act(async () => {
272+
await result.current.logout();
238273
});
239274

240-
waitFor(() => {
275+
await waitFor(() => {
241276
expect(logoutCb).not.toHaveBeenCalled();
242277
});
243278
});

packages/contact-center/store/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"dependencies": {
2323
"mobx": "6.13.5",
2424
"typescript": "5.6.3",
25-
"webex": "3.7.0-wxcc.5"
25+
"webex": "3.7.0-wxcc.6"
2626
},
2727
"devDependencies": {
2828
"@babel/core": "7.25.2",

packages/contact-center/store/src/store.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import {makeAutoObservable, observable} from 'mobx';
22
import Webex from 'webex';
3-
import {IContactCenter, Profile, Team, WithWebex, IdleCode, InitParams, IStore} from './store.types';
3+
import {
4+
IContactCenter,
5+
Profile,
6+
Team,
7+
WithWebex,
8+
IdleCode,
9+
InitParams,
10+
IStore,
11+
ILogger
12+
} from './store.types';
413

514
class Store implements IStore {
615
private static instance: Store;
716
teams: Team[] = [];
817
loginOptions: string[] = [];
918
cc: IContactCenter;
19+
logger: ILogger;
1020
idleCodes: IdleCode[] = [];
1121
agentId: string = '';
1222
selectedLoginOption: string = '';
@@ -31,18 +41,19 @@ class Store implements IStore {
3141

3242
registerCC(webex: WithWebex['webex']): Promise<void> {
3343
this.cc = webex.cc;
34-
return this.cc
35-
.register()
36-
.then((response: Profile) => {
37-
this.teams = response.teams;
38-
this.loginOptions = response.loginVoiceOptions;
39-
this.idleCodes = response.idleCodes;
40-
this.agentId = response.agentId;
41-
})
42-
.catch((error) => {
43-
console.error('Error registering contact center', error);
44-
return Promise.reject(error);
44+
this.logger = this.cc.LoggerProxy;
45+
return this.cc.register().then((response: Profile) => {
46+
this.teams = response.teams;
47+
this.loginOptions = response.loginVoiceOptions;
48+
this.idleCodes = response.idleCodes;
49+
this.agentId = response.agentId;
50+
}).catch((error) => {
51+
this.logger.error(`Error registering contact center: ${error}`, {
52+
module: 'cc-store#store.ts',
53+
method: 'registerCC',
4554
});
55+
return Promise.reject(error);
56+
});
4657
}
4758

4859
init(options: InitParams): Promise<void> {

packages/contact-center/store/src/store.types.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import {AgentLogin, IContactCenter, Profile, Team} from '@webex/plugin-cc';
1+
import {AgentLogin, IContactCenter, Profile, Team, LogContext} from '@webex/plugin-cc';
2+
3+
type ILogger = {
4+
log: (message: string, context?: LogContext) => void;
5+
info: (message: string, context?: LogContext) => void;
6+
warn: (message: string, context?: LogContext) => void;
7+
trace: (message: string, context?: LogContext) => void;
8+
error: (message: string, context?: LogContext) => void;
9+
}
210

311
interface WithWebex {
4-
webex: { cc: IContactCenter };
12+
webex: { cc: IContactCenter, logger: ILogger };
513
}
614

715
interface WithWebexConfig {
@@ -24,11 +32,12 @@ interface IStore {
2432
cc: IContactCenter;
2533
idleCodes: IdleCode[];
2634
agentId: string;
27-
35+
logger: ILogger;
2836
registerCC(webex: WithWebex['webex']): Promise<Profile>;
2937
init(params: InitParams): Promise<void>;
3038
}
3139

40+
3241
export type {
3342
IContactCenter,
3443
Profile,
@@ -37,5 +46,6 @@ export type {
3746
WithWebex,
3847
IdleCode,
3948
InitParams,
40-
IStore
41-
}
49+
IStore,
50+
ILogger,
51+
}

packages/contact-center/store/tests/store.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ jest.mock('webex', () => ({
1717
}
1818
}),
1919
cc: {
20-
register: jest.fn()
20+
register: jest.fn(),
21+
LoggerProxy: {
22+
error: jest.fn()
23+
}
2124
}
2225
}))
2326
}));
@@ -62,7 +65,6 @@ describe('Store', () => {
6265
});
6366

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

@@ -71,8 +73,10 @@ describe('Store', () => {
7173
}
7274
catch (error) {
7375
expect(error).toEqual(mockError);
74-
expect(consoleErrorSpy).toHaveBeenCalledWith('Error registering contact center', mockError);
75-
consoleErrorSpy.mockRestore();
76+
expect(store.logger.error).toHaveBeenCalledWith("Error registering contact center: Error: Register failed", {
77+
"method": "registerCC",
78+
"module": "cc-store#store.ts",
79+
});
7680
}
7781
});
7882
});

0 commit comments

Comments
 (0)