feat(station-login): e911 Modal on Desktop Station Login#719
feat(station-login): e911 Modal on Desktop Station Login#719brain-frog wants to merge 4 commits into
Conversation
- Add E911 modal state and methods to store (showE911Modal, isEmergencyModalAlreadyDisplayed) - Add User Preferences API types and interfaces for fetching/updating preferences - Implement fetchUserPreferences and updateEmergencyModalAcknowledgment in store wrapper - Create E911Modal presentational component with checkbox acknowledgment - Integrate E911Modal into StationLogin widget - Trigger E911 check after successful BROWSER login - Add unit tests for E911Modal component and store methods - Fix isEndTaskEnabled -> isEndCallEnabled typo in test fixtures The modal displays for BROWSER login if user hasn't previously acknowledged. User preferences are persisted via SDK userPreference service. Note: User Preferences API requires SDK update (pending publish of 3.12.0-next.133) Refs: CAI-7905
…xports - Rename E911Modal.tsx to e911-modal.tsx for consistency with other files - Remove index.ts barrel file, import component directly - Update cc-components index.ts to use direct imports
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2f023d32e1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| import React from 'react'; | ||
| import {render, screen, fireEvent, waitFor} from '@testing-library/react'; | ||
| import '@testing-library/jest-dom'; | ||
| import E911Modal from '../../../../src/components/StationLogin/E911Modal/E911Modal'; |
There was a problem hiding this comment.
Import the lower-case E911 modal module
The cc-components test script type-checks ./tests, but this import points to src/components/StationLogin/E911Modal/E911Modal; the only file added under that directory is e911-modal.tsx, so on the Linux/PnP workspace the unit suite fails module resolution before these tests can run. Use the actual lower-case module path.
Useful? React with 👍 / 👎.
| <Checkbox | ||
| data-testid="e911-checkbox" | ||
| checked={isChecked} | ||
| onChange={handleCheckboxChange} |
There was a problem hiding this comment.
Wire the Momentum checkbox change event
For the Momentum Checkbox used elsewhere in this package, the handler is wired through the custom-element onchange prop (see consult-transfer-popover.tsx), not React's normalized onChange. With this wiring, a browser click on the E911 checkbox will not update isChecked, leaving Save & Continue disabled and preventing agents from acknowledging the modal.
Useful? React with 👍 / 👎.
| if (desktopPrefString) { | ||
| try { | ||
| const desktopPref = JSON.parse(desktopPrefString); | ||
| runInAction(() => { | ||
| this.store.isEmergencyModalAlreadyDisplayed = desktopPref.isEmergencyModalAlreadyDisplayed ?? false; | ||
| }); |
There was a problem hiding this comment.
Reset the E911 preference when no desktop preference exists
When getUserPreference() returns no desktopPreference, this branch leaves isEmergencyModalAlreadyDisplayed at its previous value. Because the store is a singleton, after one BROWSER login sets the flag to true, a later agent/session with empty preferences can skip the E911 notification entirely; set the observable to false when the preference is missing or unparsable before checking whether to show the modal.
Useful? React with 👍 / 👎.
| }; | ||
|
|
||
| return ( | ||
| <dialog ref={dialogRef} className="e911-modal" data-testid="e911-modal"> |
There was a problem hiding this comment.
Sync native dialog closes back to the store
A native <dialog> can be closed with Escape, but this element has no close/cancel handler, so that path bypasses handleCancel: the browser hides the E911 modal without saving acknowledgment while showE911Modal remains true, and the effect will not reopen it because isOpen did not change. Add a close/cancel handler that calls the same cancel path or prevents native cancellation.
Useful? React with 👍 / 👎.
- Fix import path in e911-modal.test.tsx to match renamed component file - Update yarn.lock
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e205c18ad
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| module: 'storeEventsWrapper.ts', | ||
| method: 'fetchUserPreferences', | ||
| }); | ||
| return; |
There was a problem hiding this comment.
Avoid opening E911 when preferences cannot be saved
When cc.userPreference is absent (the service is typed optional and the public init({webex}) path can receive SDK instances without it), this early return makes fetchUserPreferences() resolve successfully while leaving the default isEmergencyModalAlreadyDisplayed = false. checkE911ModalDisplay() then opens the E911 modal, but updateEmergencyModalAcknowledgment() has the same early-return behavior, so Save & Continue silently leaves the modal open and cannot persist the acknowledgment; suppress the modal or surface a failure instead of treating this as an unchecked preference.
Useful? React with 👍 / 👎.
- Wire Momentum Checkbox via 'onchange' prop instead of React 'onChange' (custom element does not fire React's synthetic change event, leaving Save & Continue permanently disabled) - Sync native dialog 'cancel' event (Escape key) back to onCancel so store state (showE911Modal) stays consistent with dialog visibility - Reset isEmergencyModalAlreadyDisplayed to false whenever desktopPreference is missing/unparsable, instead of leaving the singleton's stale value, which could cause the modal to be skipped for a new agent/session - Throw instead of silently resolving in fetchUserPreferences and updateEmergencyModalAcknowledgment when userPreference service is unavailable, so failures are surfaced instead of leaving the modal stuck open with no way to persist acknowledgment - Add regression tests for native cancel handling and preference reset Addresses review comments on PR webex#719
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 440fa9aef6
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const desktopPreference = JSON.stringify({ | ||
| isEmergencyModalAlreadyDisplayed: true, | ||
| }); |
There was a problem hiding this comment.
Merge the E911 flag into existing desktop preferences
In updateEmergencyModalAcknowledgment, when a user already has any other fields in desktopPreference, this constructs a brand-new JSON object and sends it as the full preference payload, so acknowledging E911 deletes those sibling settings from the persisted preference record. Since fetchUserPreferences already treats desktopPreference as a JSON object and only reads the E911 property, fetch/parse the current object and spread it before setting isEmergencyModalAlreadyDisplayed.
Useful? React with 👍 / 👎.
cmullenx
left a comment
There was a problem hiding this comment.
left some comments and some of codex reviews need to be addressed as well
| .e911-modal { | ||
| padding: 0; | ||
| border: none; | ||
| border-radius: 8px; |
There was a problem hiding this comment.
can you make sure to use rems and not px and momentum colors instead of hex codes and momentum fonts, i dont think you should have to add font weights
| }; | ||
|
|
||
| return ( | ||
| <dialog ref={dialogRef} className="e911-modal" data-testid="e911-modal"> |
There was a problem hiding this comment.
doesnt momentum have a dialog component?
|
|
||
| const checkE911ModalDisplay = async () => { | ||
| try { | ||
| if (deviceType !== 'BROWSER') { |
There was a problem hiding this comment.
should browser be a const?
akulakum
left a comment
There was a problem hiding this comment.
station-login-spec.md — Spec not updated
Per repo spec-currency rules, the module spec should be updated in the same change.
Please add E911 modal requirements as new STATION-LOGIN-R-* entries in packages/contact-center/station-login/ai-docs/station-login-spec.md, including:
- Trigger conditions
- Persistence via
desktopPreference - Cancel/dismiss behavior
…and map them to the new tests.
| <Text tagname="p" type="body-midsize-regular" className="e911-warning-message"> | ||
| {E911ModalLabels.WARNING_MESSAGE} | ||
| </Text> | ||
| <a href="#" className="e911-help-link" data-testid="e911-help-link"> |
There was a problem hiding this comment.
The "See help section" link uses href="#", which doesn't navigate anywhere and can cause a page jump.
Please either:
- Wire a real help URL (via prop or constant), or
- Remove the link until a destination is available
| } | ||
| }; | ||
|
|
||
| const checkE911ModalDisplay = async () => { |
There was a problem hiding this comment.
Store and modal component are well covered, but checkE911ModalDisplay() has no unit tests.
Please add tests in tests/helper.ts for:
- Modal shown on successful BROWSER login when
isEmergencyModalAlreadyDisplayedisfalse - Modal skipped for non-BROWSER device types (
EXTENSION,AGENT_DN, etc.) - Modal skipped when preference is already acknowledged
- Graceful handling when
fetchUserPreferences()fails (error logged, modal not shown)
| }; | ||
|
|
||
| return <StationLoginComponent {...props} />; | ||
| const handleE911SaveAndContinue = async () => { |
There was a problem hiding this comment.
If updateEmergencyModalAcknowledgment() fails, the error is only logged — the modal stays open with no user feedback.
Consider showing:
- Inline error text on the modal, or
- A toast notification
…so the agent knows Save failed and can retry.
| setLoginSuccess(res); | ||
| setLoginFailure(undefined); | ||
|
|
||
| checkE911ModalDisplay(); |
There was a problem hiding this comment.
Two product-behavior questions to confirm:
Trigger scope
checkE911ModalDisplay() only runs in the stationLogin() success callback. It won't fire on:
- Page refresh when already logged in with BROWSER
AGENT_STATION_LOGIN_SUCCESS/ relogin events- Switching to BROWSER via profile save while logged in
Is that intentional, or should those paths also show the modal?
Cancel / dismiss
Cancel, X, and Escape close the modal without persisting acknowledgment — the agent stays logged in and can place calls.
Is that acceptable for E911 compliance, or should dismiss block calls / require logout until acknowledged?
COMPLETES # https://jira-eng-sjc12.cisco.com/jira/browse/CAI-7905
This pull request addresses
When a user does a "Desktop" station login in agent desktop there is supposed to be a modal asking them to fill out their emergency numbers and a value in user preferences that tracks if the modal has been acknowledged
< DESCRIBE THE CONTEXT OF THE ISSUE >
by making the following changes
Adding the modal and having it pop up in that use case
< DESCRIBE YOUR CHANGES >
https://app.vidcast.io/share/86714212-0e4c-4b4d-9173-6df14d7bf273?playerMode=vidcast
Change Type
The following scenarios were tested
< ENUMERATE TESTS PERFORMED, WHETHER MANUAL OR AUTOMATED >
The GAI Coding Policy And Copyright Annotation Best Practices
Checklist before merging
Make sure to have followed the contributing guidelines before submitting.