Skip to content

docs(ai-docs): task refactor migration — widget hooks (PR 3/4)#647

Open
akulakum wants to merge 8 commits intowebex:nextfrom
akulakum:TASK_REFACTOR_MIGRATION_WIDGET_LAYER
Open

docs(ai-docs): task refactor migration — widget hooks (PR 3/4)#647
akulakum wants to merge 8 commits intowebex:nextfrom
akulakum:TASK_REFACTOR_MIGRATION_WIDGET_LAYER

Conversation

@akulakum
Copy link
Contributor

@akulakum akulakum commented Mar 11, 2026

COMPLETES #https://jira-eng-sjc12.cisco.com/jira/browse/CAI-7714

This pull request addresses

This is PR 3 of 4 in the task refactor migration documentation series. It covers the widget hooks layeruseCallControl and useIncomingTask refactoring to consume task.uiControls instead of getControlsVisibility().

by making the following changes

Added 2 widget hook migration documents under packages/contact-center/ai-docs/migration/:

  • call-control-hook-migration.md: Refactors useCallControl (the largest hook) to consume task.uiControls:

    • Maps 22 control visibility flags to nested {isVisible, isEnabled} structure
    • Timer utils migration (calculateStateTimerData, calculateConsultTimerData)
    • Migration gotchas: UIControlConfig/agentId, isHeld derivation, recording semantics, exitConference visibility change
    • Pre-existing bug: Recording callback cleanup mismatch
    • Before/after code examples for hook and timer utils
  • incoming-task-migration.md: Replaces local isBrowser/isDeclineButtonEnabled logic with task.uiControls.accept/decline — includes before/after for hook and component

Note: task-list-migration.md and component-layer-migration.md moved to PR 4 to balance PR size.

CC SDK Task-Refactor Branch Reference

These migration docs are driven by the CC SDK task-refactor branch. Reviewers should evaluate comments against the new SDK behavior, not the old widget logic.

Change Type

  • Documentation update

Related PRs

  • PR 1/4: Foundation & Overview — #644
  • PR 2/4: Store Layer — #646
  • PR 4/4: Task List & Component Layer — #648

The following scenarios were tested

  • Documentation-only change — no functional testing required

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was used to create a draft that was subsequently customized or modified
  • Tool used for AI assistance: Other - Cursor
  • This PR is related to: Tech Debt

Checklist before merging

  • I have not skipped any automated checks
  • All existing and new tests passed

Add widget layer migration documentation:
- 004: CallControl hook migration (largest hook, timer utils, recording cleanup)
- 005: IncomingTask migration (isBrowser → task.uiControls.accept/decline)
- 006: TaskList migration (per-task accept/decline rendering)
- 007: OutdialCall migration (no changes needed — CC-level, not task-level)
- 010: Component layer migration (cc-components: call-control.utils.ts, call-control-cad.tsx, props)

Made-with: Cursor
@akulakum akulakum requested a review from a team as a code owner March 11, 2026 07:46
@aws-amplify-us-east-2
Copy link

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

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

Copy link

@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: e36142c785

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

| `isConsultInitiatedAndAccepted` | Removed — SDK handles |
| `isConsultReceived` | Removed — SDK handles |
| `isConsultInitiatedOrAccepted` | `controls.endConsult.isVisible` |
| `isHeld` | `controls.hold` state (visible + disabled = held) |

Choose a reason for hiding this comment

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

P2 Badge Derive held state from task media, not control disablement

This mapping says isHeld should come from controls.hold being visible+disabled, but that will misclassify non-held calls during consult/conference transitions where hold is intentionally disabled for other reasons (see current getHoldResumeButtonVisibility logic in task-util.ts, where isEnabled depends on consult/conference state, not only hold state). Following this guidance can invert Hold/Resume behavior in the migration; the doc should point readers to participant/media hold status (e.g., findHoldStatus) instead.

Useful? React with 👍 / 👎.

@akulakum akulakum added the validated Indicates that the PR is ready for actions label Mar 11, 2026
Copy link

@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: b62e700eb0

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return (
<div className="call-control">
{controls.hold.isVisible && (
<Button onClick={() => onToggleHold(!controls.hold.isEnabled)} disabled={!controls.hold.isEnabled}>

Choose a reason for hiding this comment

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

P1 Badge Derive hold toggles from media hold state, not enablement

This example still infers held state from controls.hold.isEnabled by calling onToggleHold(!controls.hold.isEnabled), which can invert Hold/Resume actions during consult/conference transitions where hold is disabled for reasons unrelated to held status. In the current logic (getHoldResumeButtonVisibility in task/src/Utils/task-util.ts), isEnabled depends on consult/conference predicates, so using it as a held proxy will issue the wrong SDK action in valid call states; the guidance should use actual media/participant hold status (for example findHoldStatus) for this decision.

Useful? React with 👍 / 👎.

Comment on lines +142 to +144
store.setTaskCallback(TASK_EVENTS.TASK_ASSIGNED, () => {
if (onAccepted) onAccepted({task: incomingTask});
}, incomingTask.data.interactionId);

Choose a reason for hiding this comment

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

P2 Badge Reuse a named TASK_ASSIGNED callback for removable cleanup

The migrated snippet still registers TASK_ASSIGNED with an inline function, while the documented “same as before” cleanup pattern removes TASK_ASSIGNED via taskAssignCallback; because removeTaskCallback ultimately calls task.off(event, callback) (which requires the exact same function reference), this pattern leaves stale listeners attached across task changes/unmounts and can duplicate onAccepted executions.

Useful? React with 👍 / 👎.

Move widget-layer migration docs to packages/contact-center/ai-docs/migration/.
Delete 007-outdial-call-migration.md (no task-refactor changes needed).

Made-with: Cursor
Copy link

@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: 42936f20c1

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

| Old Flag | New Approach |
|----------|-------------|
| `isConferenceInProgress` | `controls.exitConference.isVisible` |
| `isConsultInitiated` | `controls.endConsult.isVisible` |

Choose a reason for hiding this comment

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

P1 Badge Preserve consult-initiating state separately from consulting

Mapping isConsultInitiated to controls.endConsult.isVisible collapses two distinct consult phases into one signal, because end-consult visibility represents both initiated and accepted consult states (the current getEndConsultButtonVisibility already gates on initiated-or-accepted). Any migration code that uses this mapping for consult labels or branching will misclassify active consulting as “consult requested,” which changes button filtering and status text behavior in valid call flows.

Useful? React with 👍 / 👎.

Comment on lines +300 to +301
| `controlVisibility.consultTransfer.isEnabled` | `controls.consultTransfer.isEnabled` |
| `controlVisibility.consultTransfer.isVisible` | `controls.consultTransfer.isVisible` |

Choose a reason for hiding this comment

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

P1 Badge Use transfer controls instead of hidden consultTransfer control

This migration row rewires consultTransfer to controls.consultTransfer, but the same docs describe the new model as splitting transfer actions across controls.transfer and controls.transferConference while consultTransfer is hidden. Implementing this row as written will bind consult/conference transfer UI to a control that never surfaces, causing transfer actions to disappear in consult/conference scenarios.

Useful? React with 👍 / 👎.

Removed serial numbers from filenames. Added migration gotchas to
call-control-hook doc. Fixed isHeld State Flag mapping. Moved
task-list and component-layer docs to PR 4.

Made-with: Cursor
Copy link

@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: 3918b09b17

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

| `mergeConference` | `controls.mergeToConference` | **Renamed** + nested |
| `consult` | `controls.consult` | Nested |
| `endConsult` | `controls.endConsult` | Nested |
| `consultTransfer` | `controls.consultTransfer` | Nested (always hidden in new) |

Choose a reason for hiding this comment

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

P1 Badge Map consult transfer UI to active transfer controls

This row maps consultTransfer to controls.consultTransfer while simultaneously documenting that this new control is always hidden, which would remove consult/conference transfer actions when teams follow the table literally. The existing CallControl button builder currently renders transfer-in-consult from controlVisibility.consultTransfer, so wiring that path to an always-hidden control makes the transfer button disappear in active consult/conference flows; this mapping should instead point to the visible transfer controls (transfer / transferConference) used for those states.

Useful? React with 👍 / 👎.

| `isConsultReceived` | Removed — SDK handles |
| `isConsultInitiatedOrAccepted` | `controls.endConsult.isVisible` |
| `isHeld` | **Do NOT derive from `controls.hold.isEnabled`** — use `findHoldStatus(task, 'mainCall', agentId)` from task data |
| `consultCallHeld` | `controls.switchToConsult.isVisible` |

Choose a reason for hiding this comment

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

P2 Badge Derive consult-held state from media hold status

Mapping consultCallHeld to controls.switchToConsult.isVisible loses real held-state information because switch-button visibility is gated by additional UI conditions (e.g. !isBeingConsulted in getSwitchToConsultButtonVisibility) that are unrelated to whether the consult leg is actually on hold. Using this mapping will misclassify consult hold state in valid flows and can skew downstream timer/status logic that depends on consultCallHeld; it should continue to come from participant/media hold data (for example findHoldStatus(task, 'consult', agentId)).

Useful? React with 👍 / 👎.

@akulakum akulakum changed the title docs(ai-docs): task refactor migration — widget layer (PR 3/4) docs(ai-docs): task refactor migration — widget hooks (PR 3/4) Mar 12, 2026
@akulakum
Copy link
Contributor Author

@codex review

Copy link

@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: 3918b09b17

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +140 to +142
store.setTaskCallback(TASK_EVENTS.TASK_ASSIGNED, () => {
if (onAccepted) onAccepted({task: incomingTask});
}, incomingTask.data.interactionId);

Choose a reason for hiding this comment

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

P2 Badge Reuse one TASK_ASSIGNED callback for add/remove

The migrated useIncomingTask example still registers TASK_EVENTS.TASK_ASSIGNED with an inline arrow function, but cleanup is described as unchanged; that pattern cannot reliably unsubscribe because removeTaskCallback ultimately calls task.off(event, callback) and requires the same function reference used in setTaskCallback (packages/contact-center/store/src/storeEventsWrapper.ts). If this guidance is followed, changing/unmounting incomingTask can leave stale listeners behind and trigger duplicate onAccepted executions on later assignments.

Useful? React with 👍 / 👎.

…ation docs

- useCallControl: use TASK_RECORDING_PAUSED/RESUMED in removeTaskCallback so
  cleanup matches setTaskCallback (fixes listener leak)
- remove console.log from toggleMute
- tests: invoke recording callbacks via TASK_RECORDING_* to match registration
- call-control-hook-migration: document recording event alignment, add
  helper.ts code-location table, retain deviceType/featureFlags/conferenceEnabled
  for applyFeatureGates

Made-with: Cursor
Copy link

@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: 2538c8a2fa

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const onControlsUpdated = (updatedControls: TaskUIControls) => {
setControls(updatedControls);
};
task.on(TASK_EVENTS.TASK_UI_CONTROLS_UPDATED, onControlsUpdated);

Choose a reason for hiding this comment

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

P1 Badge Replace undefined TASK_UI_CONTROLS_UPDATED enum usage

This migration example subscribes with TASK_EVENTS.TASK_UI_CONTROLS_UPDATED, but that enum member does not exist in packages/contact-center/store/src/store.types.ts (the enum currently ends at TASK_OUTDIAL_FAILED). If teams follow this snippet during the refactor, TypeScript compilation fails and the uiControls update listener cannot be wired, so the guidance should either use the literal 'task:ui-controls-updated' event name or add the enum constant first.

Useful? React with 👍 / 👎.

Copy link

@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: 5cec293ab3

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!incomingTask) return;
store.setTaskCallback(TASK_EVENTS.TASK_ASSIGNED, taskAssignCallback, incomingTask.data.interactionId);
store.setTaskCallback(TASK_EVENTS.TASK_CONSULT_ACCEPTED, taskAssignCallback, incomingTask?.data.interactionId);
store.setTaskCallback(TASK_EVENTS.TASK_END, taskRejectCallback, incomingTask?.data.interactionId);

Choose a reason for hiding this comment

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

P2 Badge Declare taskRejectCallback in migrated useIncomingTask example

The “After (migrated)” snippet calls taskRejectCallback in setTaskCallback/removeTaskCallback and includes it in the effect dependency list, but the callback is never defined in the example. Because this section is presented as the full hook migration, teams copying it will get a TypeScript Cannot find name 'taskRejectCallback' error and incomplete reject/end wiring unless they guess the missing code.

Useful? React with 👍 / 👎.

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

Labels

validated Indicates that the PR is ready for actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant