Skip to content

feat(cc): add campaign preview#684

Open
cmullenx wants to merge 9 commits into
webex:nextfrom
cmullenx:chrmulle/campaignPrev
Open

feat(cc): add campaign preview#684
cmullenx wants to merge 9 commits into
webex:nextfrom
cmullenx:chrmulle/campaignPrev

Conversation

@cmullenx
Copy link
Copy Markdown
Contributor

@cmullenx cmullenx commented May 11, 2026

COMPLETES #https://jira-eng-sjc12.cisco.com/jira/browse/CAI-7660 and https://jira-eng-sjc12.cisco.com/jira/browse/CAI-7662

This pull request addresses

Adds the UI for the campaign preview functionality

by making the following changes

creates new components for campaign preview
creates global variable component to share between call control cad and campaign components
makes changes to call control cad to render campaign preview ui
adds campaign preview to task list only when flag is enabled

Figma: https://www.figma.com/design/JvnDPHRIXlvZEiSSCBwtjk/WxCC-6242---Preview-Campaign?node-id=6473-173114&m=dev

Vidcast: https://app.vidcast.io/share/72f03823-417d-4417-8a5a-35032943f3d3

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

  • The testing is done with the amplify link
    < ENUMERATE TESTS PERFORMED, WHETHER MANUAL OR AUTOMATED >

  • Can accept campaign previews

  • Can skip campaign previews

  • Can remove campaign previews

  • Can disable skip/remove buttons based on campaign settings

  • Campaign auto action fires when campaign times out

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - Windsurf
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

Checklist before merging

  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the testing document
  • I have tested the functionality with amplify link

Make sure to have followed the contributing guidelines before submitting.

@cmullenx cmullenx requested a review from a team as a code owner May 11, 2026 20:32
@cmullenx cmullenx added validated Indicates that the PR is ready for actions run_e2e Add this label to run E2E test for meeting and CC widgets labels May 11, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3cda98967

ℹ️ 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".

@aws-amplify-us-east-2
Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-684.d1b38q61t1z947.amplifyapp.com

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a2feebe73

ℹ️ 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".

Comment thread packages/contact-center/store/src/storeEventsWrapper.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 003596fba6

ℹ️ 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".

Comment on lines +91 to +94
const globalVariablesRef = useRef(latestGlobalVariables);
if (latestGlobalVariables.length > 0) {
globalVariablesRef.current = latestGlobalVariables;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reset campaign CAD when a new preview contact arrives

When Skip/Remove advances the same campaign task to another contact and the SDK update omits or empties callAssociatedData, this ref never clears because it only writes non-empty values. The component already detects new contacts via timeoutTimestamp below, but GlobalVariablesPanel will keep showing the previous contact's global variables on the next preview; reset/key the ref when the offer changes, and mirror the same fix in the popover path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 97c2c9dd1a

ℹ️ 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".

Comment thread packages/contact-center/store/src/storeEventsWrapper.ts Outdated
Copy link
Copy Markdown
Contributor

@Shreyas281299 Shreyas281299 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review.

Comment thread packages/contact-center/task/src/CallControlCAD/index.tsx Outdated
Comment thread packages/contact-center/task/src/CallControlCAD/index.tsx Outdated
Comment thread packages/contact-center/task/src/CallControl/index.tsx Outdated
Comment thread packages/contact-center/store/tests/storeEventsWrapper.ts Outdated
Comment thread packages/contact-center/task/src/CallControl/index.tsx Outdated
};

const CampaignTaskWithMetrics = withMetrics(CampaignTask, 'CampaignTask');
export default CampaignTaskWithMetrics;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we wrap this with ErrorBoundary too? The other task components all have it and if something blows up in here it'd take down the whole TaskList.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i added an ErrorBoundary to where CampaignTask is rendered

@@ -648,6 +741,36 @@ class StoreWrapper implements IStoreWrapper {
this.refreshTaskList();
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: event is untyped here — should be ITask like the other handlers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be resolved

setIsAcceptClicked(true);
setHandleTimestamp(Date.now());
disableAllButtons();
logger?.info('CC-Widgets: CampaignTask: Auto-accept UI state set, awaiting backend', {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This useState is way down here after a bunch of useEffects. Easy to miss — mind moving it up with the rest of the state declarations?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there isn't a useState down here

@cmullenx cmullenx force-pushed the chrmulle/campaignPrev branch from 97c2c9d to e8a783a Compare May 20, 2026 22:12
*/
export function isCampaignPreviewTask(task: ITask): boolean {
const outboundType = task.data.interaction.outboundType ?? '';
const cpd = task.data.interaction.callProcessingDetails as unknown as Record<string, string | undefined>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to avoid using unknown? Do you think the correct type should come from the SDK?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type doesnt come from the SDK, although we can make an udpate to the SDK to export the type as a later item

Comment thread packages/contact-center/task/src/CallControlCAD/index.tsx Outdated
Comment thread packages/contact-center/task/src/CallControl/index.tsx
Comment on lines +155 to +158
get acceptedCampaignIds() {
return this.store.acceptedCampaignIds;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a setter for this state as well??

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These get set in the addAcceptedCamapaign and removeAcceptedCampaign functions

Comment thread packages/contact-center/store/src/storeEventsWrapper.ts Outdated
Comment on lines +46 to +56
// Persist global variables across task updates — some store refreshes
// replace the task with a snapshot that omits callAssociatedData,
// which causes getAgentViewableGlobalVariables to return [].
// We intentionally keep the previous values when length === 0 because
// an empty array indicates missing data, not a legitimate clearing of
// variables. Variables are never cleared mid-call by the backend.
const globalVariablesRef = useRef(latestGlobalVariables);
if (latestGlobalVariables.length > 0) {
globalVariablesRef.current = latestGlobalVariables;
}
const globalVariables = globalVariablesRef.current;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we need to persist variables across refrershed then ideally we should put the value in the store. But if its working then we dont need to make any changes

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1406aa2787

ℹ️ 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".

Comment thread packages/contact-center/store/src/storeEventsWrapper.ts Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 97626ebe20

ℹ️ 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".

agentId,
});

if (isUnacceptedCampaignPreview(currentTask, acceptedCampaignIds)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard null currentTask before campaign preview check

CallControlCADInternal now calls isUnacceptedCampaignPreview(currentTask, acceptedCampaignIds) before verifying that currentTask exists. store.currentTask is initialized to null and can be null between interactions, so this path throws (task.data access inside isCampaignPreviewTask) whenever the widget is mounted without an active task. In apps that render CallControlCAD persistently, this causes repeated error-boundary trips and hides the component until another render with a task.

Useful? React with 👍 / 👎.

Comment on lines +253 to +259
if (
task &&
this.isCampaignPreview(task) &&
task.data.interaction.state === 'new' &&
!this.store.acceptedCampaignIds.has(task.data.interactionId)
) {
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reset current task when blocking pending campaign previews

This early return prevents assignment of a pending campaign preview, but refreshTaskList() can call setCurrentTask() after removing a previous currentTask. In that flow, returning here leaves the old task object in store.currentTask, so call-control widgets can continue rendering stale state/actions for the ended interaction until a later event updates selection. The guard should avoid promoting the preview while still clearing the prior current task.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run_e2e Add this label to run E2E test for meeting and CC widgets validated Indicates that the PR is ready for actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants