Skip to content

Commit a38cc5b

Browse files
authored
fix(station-login): doStationLogout prop to logout on signout confirm (#473)
1 parent 2f3f81f commit a38cc5b

11 files changed

Lines changed: 245 additions & 33 deletions

File tree

packages/contact-center/cc-components/src/components/StationLogin/station-login.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
handleTeamSelectChanged,
1515
saveConfirmCancelClicked,
1616
updateDialNumberLabel,
17+
handleCCSignoutKeyDown,
1718
} from './station-login.utils';
1819

1920
const StationLoginComponent: React.FunctionComponent<StationLoginComponentProps> = (props) => {
@@ -89,7 +90,7 @@ const StationLoginComponent: React.FunctionComponent<StationLoginComponentProps>
8990
<Button
9091
id="ContinueButton"
9192
data-testid="ContinueButton"
92-
onClick={() => continueClicked(multiSignInModalRef, handleContinue)}
93+
onClick={() => continueClicked(multiSignInModalRef, handleContinue, setShowCCSignOutModal)}
9394
variant="secondary"
9495
className="white-button"
9596
>
@@ -98,7 +99,12 @@ const StationLoginComponent: React.FunctionComponent<StationLoginComponentProps>
9899
</div>
99100
</dialog>
100101
{/* TODO: Replace dialog with momentum-design modal component once available */}
101-
<dialog ref={ccSignOutModalRef} className="dialog-modal" data-testid="cc-logout-modal">
102+
<dialog
103+
ref={ccSignOutModalRef}
104+
className="dialog-modal"
105+
data-testid="cc-logout-modal"
106+
onKeyDown={(e) => handleCCSignoutKeyDown(e, setShowCCSignOutModal)}
107+
>
102108
<Text tagname="h2" type="body-large-bold" className="modal-text">
103109
{StationLoginLabels.CC_SIGN_OUT}
104110
</Text>
@@ -114,7 +120,10 @@ const StationLoginComponent: React.FunctionComponent<StationLoginComponentProps>
114120
>
115121
{StationLoginLabels.CANCEL}
116122
</Button>
117-
<Button data-testId="cc-logout-button" onClick={() => continueClicked(ccSignOutModalRef, onCCSignOut)}>
123+
<Button
124+
data-testId="cc-logout-button"
125+
onClick={() => continueClicked(ccSignOutModalRef, onCCSignOut, setShowCCSignOutModal)}
126+
>
118127
{StationLoginLabels.SIGN_OUT}
119128
</Button>
120129
</div>

packages/contact-center/cc-components/src/components/StationLogin/station-login.types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ export interface IStationLoginProps {
111111
*/
112112
onCCSignOut?: () => void;
113113

114+
/**
115+
* If this boolean is false, the agent will not be logged out from the station but the onCCSignOut will be called.
116+
* By default, it is true which means the agent will be logged out from the station and onCCSignOut will be called.
117+
*/
118+
doStationLogout?: boolean;
119+
114120
/**
115121
* The team id for agent login
116122
*/

packages/contact-center/cc-components/src/components/StationLogin/station-login.utils.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const handleModals = (
3434
* Closes the dialog if it is currently open and calls the provided callback function
3535
*/
3636

37-
const continueClicked = (modalRef, callback) => {
37+
const continueClicked = (modalRef, callback, setShowCCSignOutModal) => {
38+
setShowCCSignOutModal(false);
3839
if (modalRef.current) {
3940
modalRef.current.close();
4041
callback();
@@ -219,6 +220,15 @@ const handleOnCCSignOut = (ccSignOutModalRef: React.RefObject<HTMLDialogElement>
219220
onCCSignOut();
220221
};
221222

223+
const handleCCSignoutKeyDown = (
224+
event: React.KeyboardEvent<HTMLDialogElement>,
225+
setShowCCSignOutModal: (show: boolean) => void
226+
) => {
227+
if (event.key === 'Escape') {
228+
setShowCCSignOutModal(false);
229+
}
230+
};
231+
222232
export {
223233
handleModals,
224234
continueClicked,
@@ -232,4 +242,5 @@ export {
232242
handleDNInputChanged,
233243
handleTeamSelectChanged,
234244
handleOnCCSignOut,
245+
handleCCSignoutKeyDown,
235246
};

packages/contact-center/cc-components/tests/components/StationLogin/station-login.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ describe('Station Login Component', () => {
123123
expect(ccSignOutModal).toHaveTextContent(StationLoginLabels.CC_SIGN_OUT);
124124
expect(ccSignOutModal).toHaveTextContent(StationLoginLabels.CC_SIGN_OUT_CONFIRM);
125125
expect(ccSignOutModal).toBeInTheDocument();
126+
expect(ccSignOutModal).toHaveAttribute('class', 'dialog-modal');
126127

127128
// Check Text components in cc-logout-modal
128129
const ccSignOutModalTitle = ccSignOutModal.querySelector('mdc-text[tagname="h2"]');
@@ -493,7 +494,7 @@ describe('Station Login Component', () => {
493494
);
494495
});
495496

496-
describe('SignOut Modal Popup', () => {
497+
describe('SignOut Modal Popup and handleCCSignoutKeyDown', () => {
497498
it('show signOut modal when onCCSignOut is present and cancel is clicked', async () => {
498499
const mockSignOutModalRef = {current: null};
499500
mockCreateStationLoginRefs.mockImplementation(() => ({
@@ -530,7 +531,7 @@ describe('Station Login Component', () => {
530531
expect(confirmSignOutButton).toHaveTextContent(StationLoginLabels.SIGN_OUT);
531532

532533
fireEvent.click(confirmSignOutButton);
533-
expect(mockContinueClicked).toHaveBeenCalledWith(mockSignOutModalRef, mockSignOut);
534+
expect(mockContinueClicked).toHaveBeenCalledWith(mockSignOutModalRef, mockSignOut, expect.any(Function));
534535
});
535536

536537
it('show signOut modal when onCCSignOut is present and sign out is clicked', async () => {
@@ -585,10 +586,14 @@ describe('Station Login Component', () => {
585586

586587
const continueBtn = screen.getByTestId('ContinueButton');
587588
fireEvent.click(continueBtn);
588-
expect(stationLoginUtils.continueClicked).toHaveBeenCalledWith(mockModal, handleContinue);
589+
expect(stationLoginUtils.continueClicked).toHaveBeenCalledWith(mockModal, handleContinue, expect.any(Function));
589590
});
590591

591592
it('should close sign-out modal and update state on cancel button click', async () => {
593+
const mockSetShowCCSignOutModal = jest.fn();
594+
const mockEvent = {key: 'Escape'} as React.KeyboardEvent<HTMLDialogElement>;
595+
stationLoginUtils.handleCCSignoutKeyDown(mockEvent, mockSetShowCCSignOutModal);
596+
expect(mockSetShowCCSignOutModal).toHaveBeenCalledWith(false);
592597
const screen = await render(<StationLoginComponent {...props} />);
593598
const cancelButton = screen.getByTestId('cc-cancel-button');
594599
fireEvent.click(cancelButton);

packages/contact-center/cc-components/tests/components/StationLogin/station-login.utils.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
handleDNInputChanged,
1414
handleTeamSelectChanged,
1515
handleOnCCSignOut,
16+
handleCCSignoutKeyDown,
1617
} from '../../../src/components/StationLogin/station-login.utils';
1718
import {
1819
DESKTOP,
@@ -34,6 +35,22 @@ describe('Station Login Utils', () => {
3435
jest.clearAllMocks();
3536
});
3637

38+
describe('handleCCSignoutKeyDown', () => {
39+
it('should set showCCSignOutModal to false when Escape key is pressed', () => {
40+
const mockSetShowCCSignOutModal = jest.fn();
41+
const mockEvent = {key: 'Escape'} as React.KeyboardEvent<HTMLDialogElement>;
42+
handleCCSignoutKeyDown(mockEvent, mockSetShowCCSignOutModal);
43+
expect(mockSetShowCCSignOutModal).toHaveBeenCalledWith(false);
44+
});
45+
46+
it('should not set showCCSignOutModal for other keys', () => {
47+
const mockSetShowCCSignOutModal = jest.fn();
48+
const mockEvent = {key: 'Enter'} as React.KeyboardEvent<HTMLDialogElement>;
49+
handleCCSignoutKeyDown(mockEvent, mockSetShowCCSignOutModal);
50+
expect(mockSetShowCCSignOutModal).not.toHaveBeenCalled();
51+
});
52+
});
53+
3754
describe('handleModals', () => {
3855
let mockModalRef: React.RefObject<HTMLDialogElement>;
3956
let mockCCSignOutModalRef: React.RefObject<HTMLDialogElement>;
@@ -102,19 +119,22 @@ describe('Station Login Utils', () => {
102119
} as unknown as HTMLDialogElement,
103120
};
104121
const mockHandleContinue = jest.fn();
122+
const mockSetShowCCSignOutModal = jest.fn();
105123

106-
continueClicked(mockModalRef, mockHandleContinue);
124+
continueClicked(mockModalRef, mockHandleContinue, mockSetShowCCSignOutModal);
107125

108126
expect(mockModalRef.current?.close).toHaveBeenCalled();
109127
expect(mockHandleContinue).toHaveBeenCalled();
128+
expect(mockSetShowCCSignOutModal).toHaveBeenCalledWith(false);
110129
});
111130

112131
it('should handle null ref gracefully', () => {
113132
const nullRef = {current: null};
114133
const mockHandleContinue = jest.fn();
134+
const mockSetShowCCSignOutModal = jest.fn();
115135

116136
expect(() => {
117-
continueClicked(nullRef, mockHandleContinue);
137+
continueClicked(nullRef, mockHandleContinue, mockSetShowCCSignOutModal);
118138
}).not.toThrow();
119139
});
120140
});

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

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ export const useStationLogin = (props: UseStationLoginProps) => {
1313
const dialNumber = props.dialNumber || '';
1414
const deviceType = props.deviceType || '';
1515
const teamId = props.teamId || '';
16+
const onCCSignOut = props.onCCSignOut;
17+
const doStationLogout =
18+
props.doStationLogout === undefined || props.doStationLogout === null ? true : props.doStationLogout;
1619
const [team, setTeam] = useState('');
1720
const [loginSuccess, setLoginSuccess] = useState<StationLoginSuccess>();
1821
const [loginFailure, setLoginFailure] = useState<Error>();
@@ -72,14 +75,14 @@ export const useStationLogin = (props: UseStationLoginProps) => {
7275
if (!isLoginOptionsChanged) {
7376
setSaveError('No changes detected in login options.');
7477
logger.log('No changes detected in login options.', {
75-
module: 'widget-station-login#station-login/helper.ts',
78+
module: 'widget-station-login#helper.ts',
7679
method: 'saveLoginOptions',
7780
});
7881
if (props.onSaveEnd) props.onSaveEnd(false);
7982
return;
8083
}
8184
logger.log('Saving login options:', {
82-
module: 'widget-station-login#station-login/helper.ts',
85+
module: 'widget-station-login#helper.ts',
8386
method: 'saveLoginOptions',
8487
original: originalLoginOptions,
8588
updated: currentLoginOptions,
@@ -101,14 +104,14 @@ export const useStationLogin = (props: UseStationLoginProps) => {
101104
setOriginalLoginOptions({...currentLoginOptions});
102105
setSaveError('');
103106
logger.log('Agent profile updated successfully.', {
104-
module: 'widget-station-login#station-login/helper.ts',
107+
module: 'widget-station-login#helper.ts',
105108
method: 'saveLoginOptions',
106109
});
107110
if (props.onSaveEnd) props.onSaveEnd(true);
108111
})
109112
.catch((error: Error) => {
110113
logger.error('Failed to update agent device type', error, {
111-
module: 'widget-station-login#station-login/helper.ts',
114+
module: 'widget-station-login#helper.ts',
112115
method: 'saveLoginOptions',
113116
});
114117
setSaveError(error.message || 'Failed to update device type');
@@ -134,6 +137,21 @@ export const useStationLogin = (props: UseStationLoginProps) => {
134137
}
135138
};
136139

140+
const handleCCSignOut = async () => {
141+
if (doStationLogout && store.isAgentLoggedIn) {
142+
try {
143+
await cc.stationLogout({logoutReason: 'User requested logout'});
144+
await cc.deregister();
145+
} catch (error) {
146+
logger.error(`CC-Widgets: Error during station logout: ${error}`, {
147+
module: 'widget-station-login#helper.ts',
148+
method: 'handleCCSignOut',
149+
});
150+
}
151+
}
152+
onCCSignOut();
153+
};
154+
137155
// Make sure to set the callback are same and change the logout logic
138156
useEffect(() => {
139157
store.setCCCallback(CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS, handleLogin);
@@ -152,18 +170,18 @@ export const useStationLogin = (props: UseStationLoginProps) => {
152170
await store.registerCC();
153171
if (store.isAgentLoggedIn) {
154172
logger.log(`CC-Widgets: Agent Relogin Success`, {
155-
module: 'widget-station-login#station-login/helper.ts',
173+
module: 'widget-station-login#helper.ts',
156174
method: 'handleContinue',
157175
});
158176
} else {
159177
logger.error(`Agent Relogin Failed`, {
160-
module: 'widget-station-login#station-login/helper.ts',
178+
module: 'widget-station-login#helper.ts',
161179
method: 'handleContinue',
162180
});
163181
}
164182
} catch (error) {
165183
logger.error(`CC-Widgets: Error handling agent multi login continue: ${error}`, {
166-
module: 'widget-station-login#station-login/index.tsx',
184+
module: 'widget-station-login#helper.ts',
167185
method: 'handleContinue',
168186
});
169187
}
@@ -173,7 +191,7 @@ export const useStationLogin = (props: UseStationLoginProps) => {
173191
cc.stationLogin({teamId: team, loginOption: deviceType, dialNumber})
174192
.then((res: StationLoginSuccess) => {
175193
logger.log('CC-Widgets: useStationLogin login(): stationLogin success', {
176-
module: 'station-login/helper.ts',
194+
module: 'widget-station-login#helper.ts',
177195
method: 'login',
178196
});
179197
setLoginSuccess(res);
@@ -191,13 +209,13 @@ export const useStationLogin = (props: UseStationLoginProps) => {
191209

192210
const logout = () => {
193211
logger.info('CC-Widgets: useStationLogin logout(): invoking stationLogout', {
194-
module: 'station-login/helper.ts',
212+
module: 'widget-station-login#helper.ts',
195213
method: 'logout',
196214
});
197215
cc.stationLogout({logoutReason: 'User requested logout'})
198216
.then((res: StationLogoutSuccess) => {
199217
logger.log('CC-Widgets: useStationLogin logout(): stationLogout success', {
200-
module: 'station-login/helper.ts',
218+
module: 'widget-station-login#helper.ts',
201219
method: 'logout',
202220
});
203221
setLogoutSuccess(res);
@@ -231,5 +249,6 @@ export const useStationLogin = (props: UseStationLoginProps) => {
231249
setDialNumberValue,
232250
setSelectedTeamId,
233251
selectedTeamId,
252+
onCCSignOut: onCCSignOut ? handleCCSignOut : undefined,
234253
};
235254
};

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

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

99
const StationLogin: React.FunctionComponent<StationLoginProps> = observer(
10-
({onLogin, onLogout, onCCSignOut, profileMode, onSaveStart, onSaveEnd}) => {
10+
({onLogin, onLogout, onCCSignOut, profileMode, onSaveStart, onSaveEnd, doStationLogout}) => {
1111
const {
1212
cc,
1313
teams,
@@ -33,6 +33,8 @@ const StationLogin: React.FunctionComponent<StationLoginProps> = observer(
3333
onSaveEnd,
3434
teamId,
3535
isAgentLoggedIn,
36+
onCCSignOut,
37+
doStationLogout,
3638
});
3739

3840
const dialNumberRegex = cc?.agentConfig?.regexUS;
@@ -47,7 +49,6 @@ const StationLogin: React.FunctionComponent<StationLoginProps> = observer(
4749
dialNumberRegex,
4850
isAgentLoggedIn,
4951
showMultipleLoginAlert,
50-
onCCSignOut,
5152
teamId,
5253
setTeamId,
5354
logger,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ export type UseStationLoginProps = Pick<
1212
| 'onSaveEnd'
1313
| 'teamId'
1414
| 'isAgentLoggedIn'
15+
| 'onCCSignOut'
16+
| 'doStationLogout'
1517
>;
1618

1719
export type StationLoginProps = Pick<
1820
IStationLoginProps,
19-
'onLogin' | 'onLogout' | 'onCCSignOut' | 'profileMode' | 'onSaveStart' | 'onSaveEnd' | 'teamId'
21+
'onLogin' | 'onLogout' | 'onCCSignOut' | 'profileMode' | 'onSaveStart' | 'onSaveEnd' | 'teamId' | 'doStationLogout'
2022
>;

0 commit comments

Comments
 (0)