-
Notifications
You must be signed in to change notification settings - Fork 69
fix(campaign-task): Add all global variables to campaign task #714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
258269f
748218d
8b9b173
54954e9
c48d410
8dd0586
dddad3f
e3c86d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,7 @@ | |
|
|
||
| .cad-global-variables { | ||
| margin-top: 0.5rem; | ||
| max-height: none; | ||
| } | ||
|
|
||
| /* On-hold chip styling */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,17 +51,25 @@ const CampaignTask: React.FC<CampaignTaskProps> = ({ | |
| .callAssociatedData; | ||
| const latestGlobalVariables = getAgentViewableGlobalVariables(callAssociatedData); | ||
|
|
||
| // Persist global variables across task updates — some store refreshes | ||
| // replace the task with a snapshot that omits callAssociatedData. | ||
| // Reset when the interaction changes so stale CAD from a previous task | ||
| // is never shown on a new call. | ||
| // Persist and accumulate global variables across task updates. | ||
| // Each websocket event may only carry a subset of the full | ||
| // callAssociatedData, so we merge new variables into the ref by name | ||
| // instead of replacing the whole array. This ensures all global | ||
| // variables seen during the interaction are displayed — matching the | ||
| // regular desktop behaviour. | ||
| // When length === 0 we keep previous values (missing data, not a | ||
| // legitimate clearing — variables are never cleared mid-call). | ||
| // Reset when the interaction changes so stale CAD from a previous | ||
| // task is never shown on a new call. | ||
| const globalVariablesRef = useRef(latestGlobalVariables); | ||
| const prevInteractionIdRef = useRef(interactionId); | ||
| if (prevInteractionIdRef.current !== interactionId) { | ||
| prevInteractionIdRef.current = interactionId; | ||
| globalVariablesRef.current = latestGlobalVariables; | ||
| } else if (latestGlobalVariables.length > 0) { | ||
| globalVariablesRef.current = latestGlobalVariables; | ||
| const existingMap = new Map(globalVariablesRef.current.map((v) => [v.name, v])); | ||
| latestGlobalVariables.forEach((v) => existingMap.set(v.name, v)); | ||
| globalVariablesRef.current = Array.from(existingMap.values()); | ||
|
Comment on lines
+70
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This change alters how Useful? React with 👍 / 👎. |
||
| } | ||
| const globalVariables = globalVariablesRef.current; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -512,5 +512,130 @@ describe('CallControlCADComponent', () => { | |
|
|
||
| expect(screen.queryByTestId('call-control:participants-trigger')).not.toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('should accumulate global variables across re-renders (CAI-8143)', () => { | ||
| const firstPayload: CallAssociatedDataMap = { | ||
| Global_Language: { | ||
| name: 'Global_Language', | ||
| displayName: 'Customer Language', | ||
| value: 'English', | ||
| type: 'STRING', | ||
| agentEditable: false, | ||
| agentViewable: true, | ||
| global: true, | ||
| isSecure: false, | ||
| secureKeyId: '', | ||
| secureKeyVersion: 0, | ||
| }, | ||
| }; | ||
|
|
||
| const secondPayload: CallAssociatedDataMap = { | ||
| Global_FeedbackSurveyOptIn: { | ||
| name: 'Global_FeedbackSurveyOptIn', | ||
| displayName: 'Post Call Survey Opt-in', | ||
| value: 'true', | ||
| type: 'STRING', | ||
| agentEditable: false, | ||
| agentViewable: true, | ||
| global: true, | ||
| isSecure: false, | ||
| secureKeyId: '', | ||
| secureKeyVersion: 0, | ||
| }, | ||
| }; | ||
|
|
||
| // First render with only Global_Language | ||
| const screen = render(<CallControlCADComponent {...makePropsWithCallAssociatedData(firstPayload)} />); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The Useful? React with 👍 / 👎. |
||
| expect(screen.getByText('Customer Language:')).toBeInTheDocument(); | ||
| expect(screen.getByText('English')).toBeInTheDocument(); | ||
|
|
||
| // Re-render with only Global_FeedbackSurveyOptIn (simulating a new websocket payload) | ||
| screen.rerender(<CallControlCADComponent {...makePropsWithCallAssociatedData(secondPayload)} />); | ||
|
|
||
| // Both variables should now be visible (merged, not replaced) | ||
| expect(screen.getByText('Customer Language:')).toBeInTheDocument(); | ||
| expect(screen.getByText('English')).toBeInTheDocument(); | ||
| expect(screen.getByText('Post Call Survey Opt-in:')).toBeInTheDocument(); | ||
| expect(screen.getByText('true')).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('should update existing variable values when re-rendered with new data (CAI-8143)', () => { | ||
| const initialPayload: CallAssociatedDataMap = { | ||
| Global_Language: { | ||
| name: 'Global_Language', | ||
| displayName: 'Customer Language', | ||
| value: 'English', | ||
| type: 'STRING', | ||
| agentEditable: false, | ||
| agentViewable: true, | ||
| global: true, | ||
| isSecure: false, | ||
| secureKeyId: '', | ||
| secureKeyVersion: 0, | ||
| }, | ||
| }; | ||
|
|
||
| const updatedPayload: CallAssociatedDataMap = { | ||
| Global_Language: { | ||
| name: 'Global_Language', | ||
| displayName: 'Customer Language', | ||
| value: 'Spanish', | ||
| type: 'STRING', | ||
| agentEditable: false, | ||
| agentViewable: true, | ||
| global: true, | ||
| isSecure: false, | ||
| secureKeyId: '', | ||
| secureKeyVersion: 0, | ||
| }, | ||
| }; | ||
|
|
||
| const screen = render(<CallControlCADComponent {...makePropsWithCallAssociatedData(initialPayload)} />); | ||
| expect(screen.getByText('English')).toBeInTheDocument(); | ||
|
|
||
| // Re-render with updated value for the same variable | ||
| screen.rerender(<CallControlCADComponent {...makePropsWithCallAssociatedData(updatedPayload)} />); | ||
| expect(screen.getByText('Spanish')).toBeInTheDocument(); | ||
| expect(screen.queryByText('English')).not.toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('should reset global variables when interaction changes (CAI-8143)', () => { | ||
| const payload: CallAssociatedDataMap = { | ||
| Global_Language: { | ||
| name: 'Global_Language', | ||
| displayName: 'Customer Language', | ||
| value: 'English', | ||
| type: 'STRING', | ||
| agentEditable: false, | ||
| agentViewable: true, | ||
| global: true, | ||
| isSecure: false, | ||
| secureKeyId: '', | ||
| secureKeyVersion: 0, | ||
| }, | ||
| }; | ||
|
|
||
| const screen = render(<CallControlCADComponent {...makePropsWithCallAssociatedData(payload)} />); | ||
| expect(screen.getByText('Customer Language:')).toBeInTheDocument(); | ||
|
|
||
| // Re-render with a different interaction ID and no global variables | ||
| const newInteractionProps = { | ||
| ...defaultProps, | ||
| currentTask: { | ||
| ...defaultProps.currentTask, | ||
| data: { | ||
| ...defaultProps.currentTask.data, | ||
| interaction: { | ||
| ...defaultProps.currentTask.data.interaction, | ||
| interactionId: 'new-interaction-456', | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
| screen.rerender(<CallControlCADComponent {...newInteractionProps} />); | ||
|
|
||
| // Old variables should be cleared for the new interaction | ||
| expect(screen.queryByText('Customer Language:')).not.toBeInTheDocument(); | ||
| }); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a preview campaign offer is skipped or removed, this component can receive a new contact on the same task/interaction; the component already detects that scenario below via
campaignPreviewOfferTimeout. Because this accumulator only resets oninteractionIdchanges and otherwise merges by variable name, any variable that was present only on the previous contact remains visible in the inline panel (and the mirrored popover accumulator has the same behavior) until unmount. For example, contact A'sGlobal_Languagewill still display for contact B if B's payload contains onlyGlobal_Account, leaking stale customer data.Useful? React with 👍 / 👎.