Status: Done. The store's storeEventsWrapper.ts registers per-task SDK event handlers via registerTaskEventListeners(). The SDK state machine owns transitions and task.uiControls; the store mirrors task inventory through refreshTaskList() and fires optional host callbacks.
Core behaviors implemented:
- SDK
TASK_EVENTSenum — imported via@webex/cc-store(local enum removed) refreshTaskList()— kept in handlers; re-syncs MobXtaskList/currentTaskTASK_UI_CONTROLS_UPDATED—handleUIControlsUpdated→refreshTaskList()handleConsultEnd— wired toTASK_CONSULT_END(no longer dead code)TASK_SWITCH_CALL—handleSwitchCall→refreshTaskList()- Legacy bridge:
handleAutoAnswerstill setsisDeclineButtonEnabled; widgets also readtask.uiControls.main.decline.isEnabled
Entry point: registerTaskEventListeners(task) in storeEventsWrapper.ts. Cleanup: handleTaskRemove(taskToRemove).
| Event | Handler | Behavior |
|---|---|---|
TASK_END |
handleTaskEnd |
setIsDeclineButtonEnabled(false) + refreshTaskList() |
TASK_ASSIGNED |
handleTaskAssigned |
Set ENGAGED state, setCurrentTask, onTaskAssigned |
TASK_REJECT |
handleTaskReject |
onTaskRejected(task, reason) + refreshTaskList() |
TASK_OUTDIAL_FAILED |
handleOutdialFailed |
onOutdialFailed(reason) only — no refreshTaskList() in handler |
TASK_UI_CONTROLS_UPDATED |
handleUIControlsUpdated |
refreshTaskList() |
| SDK event | Store handler | Host / widget effect |
|---|---|---|
TASK_OUTDIAL_FAILED |
handleOutdialFailed |
Host failure modal via setOutdialFailed(reason) |
TASK_OUTDIAL_FAILED |
(widget) taskRejectCallback |
IncomingTask dismiss via setTaskCallback in useIncomingTask |
TASK_REJECT |
handleTaskReject |
Host "Task Rejected" popup via setTaskRejected |
TASK_END |
handleTaskEnd |
Cleanup + refresh — no rejection popup |
Double-popup context: SDK uses emitTaskEnd (not emitTaskReject) on OUTBOUND_FAILED so only TASK_OUTDIAL_FAILED shows the failure modal. A planned widgets-side dedup exists if SDK reverts to emitTaskReject.
CC-level handlers (after agent login): TASK_INCOMING → handleIncomingTask, TASK_HYDRATE, TASK_MERGED.
| File | Action |
|---|---|
store/src/storeEventsWrapper.ts |
Update event names to SDK names. Keep refreshTaskList() in existing handlers. Add TASK_UI_CONTROLS_UPDATED listener. Wire handleConsultEnd to TASK_CONSULT_END (fix dead code). Remove setIsDeclineButtonEnabled from handleAutoAnswer. |
store/src/store.ts |
No changes expected (observables stay). Mark isDeclineButtonEnabled for removal once widget layer uses uiControls.decline.isEnabled. |
store/src/store.types.ts |
Delete local TASK_EVENTS enum; import from SDK: import { TASK_EVENTS } from '@webex/contact-center';. |
Task-layer consumers of TASK_EVENTS |
Must be updated in the same step so that removing the store's local enum does not break the build. task/src/helper.ts imports TASK_EVENTS from @webex/cc-store and uses legacy names: AGENT_WRAPPEDUP, CONTACT_RECORDING_PAUSED, CONTACT_RECORDING_RESUMED. Replace with SDK names: TASK_WRAPPEDUP, TASK_RECORDING_PAUSED, TASK_RECORDING_RESUMED. |
store/tests/* |
Update tests for renamed events, new TASK_UI_CONTROLS_UPDATED handler, handleConsultEnd wiring fix, handleAutoAnswer change |
The SDK exports TASK_EVENTS from its package entry point (packages/@webex/contact-center/src/index.ts):
export {TASK_EVENTS} from './services/task/types';
export type {TASK_EVENTS as TaskEvents} from './services/task/types';Action: Delete the local TASK_EVENTS enum from store/src/store.types.ts and import from SDK: import { TASK_EVENTS } from '@webex/contact-center';. If the widgets repo depends on an older SDK that does not re-export TASK_EVENTS, keep the local enum and align event string values until the dependency is updated.
Sourced from the SDK task-refactor branch. Events are emitted from Task (lifecycle) and Voice (media/telephony) layers.
Task lifecycle events (from Task.ts):
| SDK Event | String Value |
|---|---|
TASK_INCOMING |
'task:incoming' |
TASK_HYDRATE |
'task:hydrate' |
TASK_OFFER_CONTACT |
'task:offerContact' |
TASK_ASSIGNED |
'task:assigned' |
TASK_END |
'task:end' |
TASK_OFFER_CONSULT |
'task:offerConsult' |
TASK_CONSULT_CREATED |
'task:consultCreated' |
TASK_CONSULT_ACCEPTED |
'task:consultAccepted' |
TASK_CONSULT_END |
'task:consultEnd' |
TASK_CONSULT_QUEUE_CANCELLED |
'task:consultQueueCancelled' |
TASK_CONSULT_QUEUE_FAILED |
'task:consultQueueFailed' |
TASK_WRAPPEDUP |
'task:wrappedup' |
Voice / media events (from Voice.ts):
| SDK Event | String Value |
|---|---|
TASK_HOLD |
'task:hold' |
TASK_RESUME |
'task:resume' |
TASK_RECORDING_STARTED |
'task:recordingStarted' |
TASK_RECORDING_PAUSED |
'task:recordingPaused' |
TASK_RECORDING_PAUSE_FAILED |
'task:recordingPauseFailed' |
TASK_RECORDING_RESUMED |
'task:recordingResumed' |
TASK_RECORDING_RESUME_FAILED |
'task:recordingResumeFailed' |
TASK_PARTICIPANT_JOINED |
'task:participantJoined' |
TASK_PARTICIPANT_LEFT |
'task:participantLeft' |
TASK_CONFERENCE_STARTED |
'task:conferenceStarted' |
TASK_CONFERENCE_ENDED |
'task:conferenceEnded' |
TASK_CONFERENCE_FAILED |
'task:conferenceFailed' |
TASK_EXIT_CONFERENCE |
'task:exitConference' |
TASK_TRANSFER_CONFERENCE |
'task:transferConference' |
TASK_SWITCH_CALL |
'task:switchCall' |
TASK_CONFERENCE_TRANSFER_FAILED |
'task:conferenceTransferFailed' |
TASK_OUTDIAL_FAILED |
'task:outdialFailed' |
Additional events (in TASK_EVENTS enum, emitted from TaskManager or other layers):
| SDK Event | String Value | Note |
|---|---|---|
TASK_MEDIA |
'task:media' |
Browser WebRTC remote media |
TASK_AUTO_ANSWERED |
'task:autoAnswered' |
Auto-answer notification |
TASK_REJECT |
'task:rejected' |
Task rejected |
TASK_MERGED |
'task:merged' |
Task merged |
TASK_POST_CALL_ACTIVITY |
'task:postCallActivity' |
Post-call activity |
TASK_CONFERENCE_ESTABLISHING |
'task:conferenceEstablishing' |
Conference in progress |
TASK_CONFERENCE_END_FAILED |
'task:conferenceEndFailed' |
Conference end failure |
TASK_PARTICIPANT_LEFT_FAILED |
'task:participantLeftFailed' |
Participant removal failure |
TASK_CONFERENCE_TRANSFERRED |
'task:conferenceTransferred' |
Conference transferred |
TASK_UI_CONTROLS_UPDATED |
'task:ui-controls-updated' |
UI controls recomputed — must subscribe |
TASK_UNASSIGNED |
'task:unassigned' |
Evaluate if widget needs to handle |
TASK_WRAPUP |
'task:wrapup' |
Evaluate if widget needs to handle |
TASK_CONSULTING |
'task:consulting' |
Consulting state entered |
The widget's local TASK_EVENTS enum (in store/src/store.types.ts) uses CC-level naming that differs from the SDK's task-level naming.
| Old (Widget) | Old Value | New (SDK) | New Value |
|---|---|---|---|
AGENT_WRAPPEDUP |
'AgentWrappedUp' |
TASK_WRAPPEDUP |
'task:wrappedup' |
AGENT_CONSULT_CREATED |
'AgentConsultCreated' |
TASK_CONSULT_CREATED |
'task:consultCreated' |
AGENT_OFFER_CONTACT |
'AgentOfferContact' |
TASK_OFFER_CONTACT |
'task:offerContact' |
These are incorrect names in the widget's local enum that already differed from the SDK. They are not renames introduced by the task-refactor; the SDK has always used the task:* naming for these.
| Old (Widget) | Old Value | Correct (SDK) | SDK Value |
|---|---|---|---|
CONTACT_RECORDING_PAUSED |
'ContactRecordingPaused' |
TASK_RECORDING_PAUSED |
'task:recordingPaused' |
CONTACT_RECORDING_RESUMED |
'ContactRecordingResumed' |
TASK_RECORDING_RESUMED |
'task:recordingResumed' |
| Widget Enum Member | Value | Note |
|---|---|---|
TASK_UNHOLD |
'task:unhold' |
SDK uses TASK_RESUME ('task:resume') instead |
TASK_CONSULT |
'task:consult' |
No SDK equivalent; consult flow uses multiple events |
TASK_PAUSE |
'task:pause' |
No SDK equivalent; SDK uses TASK_HOLD ('task:hold') |
AGENT_CONTACT_ASSIGNED |
'AgentContactAssigned' |
SDK uses TASK_ASSIGNED ('task:assigned') |
Docs to update when migrating event names: CallControl widget spec references TASK_CONSULT (and related consult flow) in its sequence diagram — see packages/contact-center/task/ai-docs/widgets/CallControl/ARCHITECTURE.md (consult sequence around line 169). Update that doc to use SDK event names and remove references to store-only enum members (TASK_CONSULT, TASK_UNHOLD) once the migration is applied.
- SDK state machine handles all transitions internally
task.datais updated by the state machine'supdateTaskDataaction on every eventtask.uiControlsis recomputed after every state transitiontask:ui-controls-updatedis emitted when controls change
refreshTaskList() is kept in all handlers that already call it. Removing refreshTaskList() is a future widget optimization, not part of this task-refactor migration (see Future Optimization below).
These handlers are unchanged by the migration. Event names already match the SDK.
| # | Event | Handler | Detail |
|---|---|---|---|
| 1 | TASK_END |
handleTaskEnd |
Remove from task list, clear current task |
| 2 | TASK_ASSIGNED |
handleTaskAssigned |
Update task list, set current task |
| 3 | TASK_REJECT |
handleTaskReject |
Remove from task list |
| 4 | TASK_OUTDIAL_FAILED |
handleOutdialFailed |
Remove from task list |
| 5 | TASK_MEDIA |
handleTaskMedia |
Browser-only WebRTC setup — not task-refactor related |
| 6 | TASK_CONSULT_QUEUE_CANCELLED |
handleConsultQueueCancelled |
Consult state reset + refreshTaskList() |
| 7 | TASK_CONSULTING |
handleConsulting |
setConsultStartTimeStamp(Date.now()) + refreshTaskList() |
| 8 | TASK_CONSULT_ACCEPTED |
handleConsultAccepted |
setConsultStartTimeStamp(Date.now()) + refreshTaskList() + TASK_MEDIA listener (browser) |
| 9 | TASK_OFFER_CONSULT |
handleConsultOffer |
refreshTaskList() |
| 10 | TASK_PARTICIPANT_JOINED |
handleConferenceStarted |
Consult state reset + refreshTaskList() |
| 11 | TASK_CONFERENCE_STARTED |
handleConferenceStarted |
Same as #10 |
| 12 | TASK_CONFERENCE_ENDED |
handleConferenceEnded |
refreshTaskList() |
| 13 | TASK_PARTICIPANT_LEFT |
handleConferenceEnded |
Same as #12 |
| 14 | TASK_HOLD |
refreshTaskList |
Re-fetch all tasks |
| 15 | TASK_RESUME |
refreshTaskList |
Re-fetch all tasks |
| 16 | TASK_POST_CALL_ACTIVITY |
refreshTaskList |
Re-fetch all tasks |
| 17 | TASK_CONFERENCE_ESTABLISHING |
refreshTaskList |
Re-fetch all tasks |
| 18 | TASK_CONFERENCE_FAILED |
refreshTaskList |
Re-fetch all tasks |
| 19 | TASK_CONFERENCE_END_FAILED |
refreshTaskList |
Re-fetch all tasks |
| 20 | TASK_PARTICIPANT_LEFT_FAILED |
refreshTaskList |
Re-fetch all tasks |
| 21 | TASK_CONFERENCE_TRANSFERRED |
refreshTaskList |
Re-fetch all tasks |
| 22 | TASK_CONFERENCE_TRANSFER_FAILED |
refreshTaskList |
Re-fetch all tasks |
| # | Event | Handler | Category | Detail |
|---|---|---|---|---|
| 23 | TASK_WRAPPEDUP |
refreshTaskList |
Task-refactor | Rename from AGENT_WRAPPEDUP. Handler unchanged. |
| 24 | TASK_CONSULT_CREATED |
handleConsultCreated |
Task-refactor | Rename from AGENT_CONSULT_CREATED. Handler unchanged — setConsultStartTimeStamp(Date.now()) + refreshTaskList(). |
| 25 | TASK_OFFER_CONTACT |
refreshTaskList |
Task-refactor | Rename from AGENT_OFFER_CONTACT. Handler unchanged. |
| 26 | TASK_RECORDING_PAUSED |
refreshTaskList |
Pre-existing fix | Fix name from CONTACT_RECORDING_PAUSED. Handler unchanged. |
| 27 | TASK_RECORDING_RESUMED |
refreshTaskList |
Pre-existing fix | Fix name from CONTACT_RECORDING_RESUMED. Handler unchanged. |
| 28 | TASK_CONSULT_END |
handleConsultEnd |
Pre-existing fix | Fix wiring — wire the existing (currently dead) handleConsultEnd method instead of bare refreshTaskList. |
| 29 | TASK_AUTO_ANSWERED |
handleAutoAnswer |
Task-refactor | Remove setIsDeclineButtonEnabled(true) — replace with task.uiControls.decline.isEnabled. Keep refreshTaskList(). |
| # | Event | Handler | Category | Detail |
|---|---|---|---|---|
| 30 | TASK_UI_CONTROLS_UPDATED |
New handler | Task-refactor | Fire callbacks to trigger widget re-renders when SDK recomputes uiControls |
refreshTaskList() is kept in all existing handlers for this migration. The store does not directly observe task.data via MobX, so refreshTaskList() is the mechanism that re-syncs the store's observable taskList and triggers MobX-driven re-renders. Removing it is a separate widget-layer optimization — not part of the task-refactor migration.
Scope: Widget improvement — not part of this migration.
Once the widget layer is updated to derive UI state from task.data / task.uiControls directly (via callbacks or by making the cc object MobX-observable), refreshTaskList() calls can be removed from most handlers. Until then, the current approach of calling refreshTaskList() on every event is safe and correct.
Why it could be removed in the future:
- SDK keeps the same task reference up to date. The state machine updates
task.data(andtask.uiControls) on the sameITaskreference already held in the store'staskList. - Widget re-renders could be driven by callbacks. Widgets registered via
setTaskCallback(event, cb, taskId)are notified when the store fires callbacks. Those callbacks could cause the widget to re-read the latesttask.datadirectly. - Re-fetch would only be needed when the list membership changes (initial load, full refresh, or
TASK_WRAPPEDUP).
The store currently has an isDeclineButtonEnabled observable set by handleAutoAnswer. With the SDK task-refactor, task.uiControls.decline.isEnabled is recomputed by the SDK and should be the source of truth for decline button state.
Current consumers:
store/src/store.ts— observable propertystoreEventsWrapper.ts— getter +setIsDeclineButtonEnabled()settertask/src/helper.ts— readsstore.isDeclineButtonEnabledand passes to widgetcc-components/.../TaskList/task-list.utils.ts—!store.isDeclineButtonEnabledfor auto-answer disable logiccc-components/.../IncomingTask/incoming-task.utils.tsx—isDeclineButtonEnabledprop
Migration steps:
- Update
handleAutoAnswerto removesetIsDeclineButtonEnabled(true)— no store mutation needed. - Update
task/src/helper.tsto readtask.uiControls.decline.isEnabledinstead ofstore.isDeclineButtonEnabled. - Update IncomingTask and TaskList components to read from
task.uiControls.decline.isEnabled. - Once no consumers remain, delete the store property, getter, and setter.
The store tracks consult state via three observables (consultStartTimeStamp, isQueueConsultInProgress, currentConsultQueueId) that are mutated by handleConsultCreated, handleConsulting, handleConsultAccepted, handleConsultEnd, handleConsultQueueCancelled, and handleConferenceStarted.
With the SDK task-refactor, consult state is tracked in task.data and task.uiControls. These store observables are retained for now because widget consult timer logic (timer-utils.ts, CallControl/index.tsx) reads consultStartTimeStamp directly.
End state: Once widgets derive consult timing from task.data (or the SDK exposes consult start time), these store properties and their setters in handleConferenceStarted and other handlers can be removed.
These are bugs in the current widget code, not introduced by the task-refactor. They should be fixed during migration but are not task-refactor changes.
A handleConsultEnd method exists (resets isQueueConsultInProgress, currentConsultQueueId, consultStartTimeStamp) but TASK_CONSULT_END is wired to refreshTaskList() instead. The method's consult state cleanup never runs.
Migration / test plan: When wiring TASK_CONSULT_END to handleConsultEnd, update store unit tests to assert the new wiring and consult state reset. Remove or rewrite tests that only covered the old dead path.
registerTaskEventListeners wires TASK_CONFERENCE_TRANSFERRED → this.refreshTaskList. But handleTaskRemove calls taskToRemove.off(TASK_EVENTS.TASK_CONFERENCE_TRANSFERRED, this.handleConferenceEnded) — wrong handler reference. This listener is never actually removed, causing a listener leak.
TASK_CONFERENCE_TRANSFERRED currently has no unit test (registration and cleanup). Tracked by (Jira: CAI-7758). When implementing the migration, add tests for this event.
File: packages/contact-center/store/src/storeEventsWrapper.ts
Register: registerTaskEventListeners(task: ITask) — registers 27 event listeners
Cleanup: handleTaskRemove(taskToRemove: ITask) — unregisters all listeners + resets state
- On task creation, store registers individual listeners for 27 task events
- Each handler manually updates store observables (
taskList,currentTask,consultStartTimeStamp,isQueueConsultInProgress,currentConsultQueueId) - Many handlers simply call
refreshTaskList()to re-fetch task state - Some handlers have specialized logic (consult, conference lifecycle)
- Widgets subscribe to store callbacks via
setTaskCallback(event, cb, taskId)
| Observable | Type | Mutated By |
|---|---|---|
currentTask |
ITask | null |
handleTaskAssigned, handleTaskEnd, handleTaskRemove |
taskList |
Record<string, ITask> |
refreshTaskList |
consultStartTimeStamp |
number | undefined |
handleConsultCreated, handleConsulting, handleConsultAccepted, handleConsultEnd, handleConsultQueueCancelled, handleConferenceStarted |
isQueueConsultInProgress |
boolean |
handleConsultEnd, handleConsultQueueCancelled, handleConferenceStarted |
currentConsultQueueId |
string |
handleConsultEnd, handleConsultQueueCancelled, handleConferenceStarted |
isDeclineButtonEnabled |
boolean |
handleAutoAnswer — migrate to task.uiControls.decline.isEnabled |
| # | Event | Handler | Action |
|---|---|---|---|
| 1 | TASK_END |
handleTaskEnd |
Remove task from list, clear current task |
| 2 | TASK_ASSIGNED |
handleTaskAssigned |
Update task list, set current task |
| 3 | AGENT_OFFER_CONTACT |
refreshTaskList |
Re-fetch all tasks |
| 4 | AGENT_CONSULT_CREATED |
handleConsultCreated |
refreshTaskList() + setConsultStartTimeStamp(Date.now()) |
| 5 | TASK_CONSULT_QUEUE_CANCELLED |
handleConsultQueueCancelled |
Reset isQueueConsultInProgress, currentConsultQueueId, consultStartTimeStamp + refreshTaskList() |
| 6 | TASK_REJECT |
handleTaskReject |
Remove task, fire callbacks |
| 7 | TASK_OUTDIAL_FAILED |
handleOutdialFailed |
Remove task, fire callbacks |
| 8 | AGENT_WRAPPEDUP |
refreshTaskList |
Re-fetch all tasks |
| 9 | TASK_CONSULTING |
handleConsulting |
refreshTaskList() + setConsultStartTimeStamp(Date.now()) |
| 10 | TASK_CONSULT_ACCEPTED |
handleConsultAccepted |
refreshTaskList() + setConsultStartTimeStamp(Date.now()) + set ENGAGED state + registers TASK_MEDIA listener on consult task (browser only) |
| 11 | TASK_OFFER_CONSULT |
handleConsultOffer |
refreshTaskList() |
| 12 | TASK_AUTO_ANSWERED |
handleAutoAnswer |
setIsDeclineButtonEnabled(true) + refreshTaskList() |
| 13 | TASK_CONSULT_END |
refreshTaskList |
Re-fetch all tasks (Note: handleConsultEnd method exists but is NOT wired — see pre-existing bug) |
| 14 | TASK_HOLD |
refreshTaskList |
Re-fetch all tasks |
| 15 | TASK_RESUME |
refreshTaskList |
Re-fetch all tasks |
| 16 | TASK_CONFERENCE_ENDED |
handleConferenceEnded |
refreshTaskList() |
| 17 | TASK_CONFERENCE_END_FAILED |
refreshTaskList |
Re-fetch all tasks |
| 18 | TASK_CONFERENCE_ESTABLISHING |
refreshTaskList |
Re-fetch all tasks |
| 19 | TASK_CONFERENCE_FAILED |
refreshTaskList |
Re-fetch all tasks |
| 20 | TASK_PARTICIPANT_JOINED |
handleConferenceStarted |
Reset isQueueConsultInProgress, currentConsultQueueId, consultStartTimeStamp + refreshTaskList() |
| 21 | TASK_PARTICIPANT_LEFT |
handleConferenceEnded |
refreshTaskList() |
| 22 | TASK_PARTICIPANT_LEFT_FAILED |
refreshTaskList |
Re-fetch all tasks |
| 23 | TASK_CONFERENCE_STARTED |
handleConferenceStarted |
(same as #20) |
| 24 | TASK_CONFERENCE_TRANSFERRED |
refreshTaskList |
Re-fetch all tasks |
| 25 | TASK_CONFERENCE_TRANSFER_FAILED |
refreshTaskList |
Re-fetch all tasks |
| 26 | TASK_POST_CALL_ACTIVITY |
refreshTaskList |
Re-fetch all tasks |
| 27 | TASK_MEDIA |
handleTaskMedia |
Browser-only: setCallControlAudio(new MediaStream([track])) |
This section provides code-level guidance for the implementing developer. The core migration: switch to SDK event names, keep refreshTaskList(), add TASK_UI_CONTROLS_UPDATED, fix TASK_CONSULT_END wiring, and replace isDeclineButtonEnabled.
registerTaskEventListeners(task: ITask) {
const interactionId = task.data.interactionId;
task.on(TASK_EVENTS.TASK_END, this.handleTaskEnd);
task.on(TASK_EVENTS.TASK_ASSIGNED, this.handleTaskAssigned);
task.on(TASK_EVENTS.AGENT_OFFER_CONTACT, this.refreshTaskList); // old name
task.on(TASK_EVENTS.AGENT_CONSULT_CREATED, this.handleConsultCreated); // old name
task.on(TASK_EVENTS.AGENT_WRAPPEDUP, this.refreshTaskList); // old name
task.on(TASK_EVENTS.TASK_CONSULT_END, this.refreshTaskList); // BUG: handleConsultEnd exists but not wired
task.on(TASK_EVENTS.CONTACT_RECORDING_PAUSED, this.refreshTaskList); // wrong name
task.on(TASK_EVENTS.CONTACT_RECORDING_RESUMED, this.refreshTaskList);// wrong name
// ... remaining events unchanged
}registerTaskEventListeners(task: ITask) {
const interactionId = task.data.interactionId;
// Lifecycle (unchanged handlers)
task.on(TASK_EVENTS.TASK_END, this.handleTaskEnd);
task.on(TASK_EVENTS.TASK_ASSIGNED, this.handleTaskAssigned);
task.on(TASK_EVENTS.TASK_REJECT, this.handleTaskReject);
task.on(TASK_EVENTS.TASK_OUTDIAL_FAILED, this.handleOutdialFailed);
// NEW: SDK-computed UI control updates
task.on(TASK_EVENTS.TASK_UI_CONTROLS_UPDATED, /* fire callbacks for this task */);
// RENAMED events (handler unchanged, refreshTaskList kept)
task.on(TASK_EVENTS.TASK_WRAPPEDUP, this.refreshTaskList); // was AGENT_WRAPPEDUP
task.on(TASK_EVENTS.TASK_CONSULT_CREATED, this.handleConsultCreated); // was AGENT_CONSULT_CREATED
task.on(TASK_EVENTS.TASK_OFFER_CONTACT, this.refreshTaskList); // was AGENT_OFFER_CONTACT
// FIX: Wire handleConsultEnd (was dead code — wired to refreshTaskList before)
task.on(TASK_EVENTS.TASK_CONSULT_END, this.handleConsultEnd);
// FIX: Correct event names (handler unchanged)
task.on(TASK_EVENTS.TASK_RECORDING_PAUSED, this.refreshTaskList); // was CONTACT_RECORDING_PAUSED
task.on(TASK_EVENTS.TASK_RECORDING_RESUMED, this.refreshTaskList); // was CONTACT_RECORDING_RESUMED
// Auto-answer — remove setIsDeclineButtonEnabled, keep refreshTaskList
task.on(TASK_EVENTS.TASK_AUTO_ANSWERED, this.handleAutoAnswer);
// Consult/conference handlers (unchanged — keep refreshTaskList + state mutations)
task.on(TASK_EVENTS.TASK_CONSULTING, this.handleConsulting);
task.on(TASK_EVENTS.TASK_CONSULT_ACCEPTED, this.handleConsultAccepted);
task.on(TASK_EVENTS.TASK_CONSULT_QUEUE_CANCELLED, this.handleConsultQueueCancelled);
task.on(TASK_EVENTS.TASK_PARTICIPANT_JOINED, this.handleConferenceStarted);
task.on(TASK_EVENTS.TASK_CONFERENCE_STARTED, this.handleConferenceStarted);
task.on(TASK_EVENTS.TASK_CONFERENCE_ENDED, this.handleConferenceEnded);
task.on(TASK_EVENTS.TASK_PARTICIPANT_LEFT, this.handleConferenceEnded);
task.on(TASK_EVENTS.TASK_OFFER_CONSULT, this.handleConsultOffer);
// Events wired to refreshTaskList (unchanged)
task.on(TASK_EVENTS.TASK_HOLD, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_RESUME, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_POST_CALL_ACTIVITY, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_CONFERENCE_ESTABLISHING, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_CONFERENCE_FAILED, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_CONFERENCE_END_FAILED, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_PARTICIPANT_LEFT_FAILED, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_CONFERENCE_TRANSFERRED, this.refreshTaskList);
task.on(TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, this.refreshTaskList);
// Browser-only: WebRTC media setup (unchanged)
if (this.deviceType === DEVICE_TYPE_BROWSER) {
task.on(TASK_EVENTS.TASK_MEDIA, this.handleTaskMedia);
}
}Note on handler references and
.off()cleanup: The implementing developer must ensure that handler references registered viatask.on()match those used inhandleTaskRemovefor.off(). This is a standard listener pattern — see the old code's existing approach for reference.
handleConferenceStarted is unchanged by this migration. Consult state resets and refreshTaskList() are both retained.
handleConferenceStarted = () => {
runInAction(() => {
this.setIsQueueConsultInProgress(false);
this.setCurrentConsultQueueId(null);
this.setConsultStartTimeStamp(null);
});
this.refreshTaskList();
};handleAutoAnswer = () => {
this.setIsDeclineButtonEnabled(true);
this.refreshTaskList();
};handleAutoAnswer = () => {
this.setIsDeclineButtonEnabled(true); // Legacy bridge — widgets also use uiControls.main.decline.isEnabled
this.refreshTaskList();
};| Criterion | Status |
|---|---|
SDK TASK_EVENTS enum used (TASK_WRAPPEDUP, TASK_CONSULT_CREATED, etc.) |
Done |
Local TASK_EVENTS removed; imported from SDK via @webex/cc-store |
Done |
refreshTaskList() retained in handlers |
Done |
TASK_UI_CONTROLS_UPDATED → handleUIControlsUpdated |
Done |
handleConsultEnd wired to TASK_CONSULT_END |
Done |
handleAutoAnswer uses only uiControls.decline.isEnabled |
Legacy — store flag still set; widgets OR with SDK control |
handleConsultAccepted registers TASK_MEDIA (browser) |
Done |
| Task list sync on lifecycle events | Done |
| Consult/conference/hold flows | Done |
handleTaskRemove listener cleanup |
Open — TASK_CONFERENCE_TRANSFERRED .off() uses wrong handler ref (listener leak) |
Task-layer SDK event names in helper.ts |
Done |
handleTaskRemovelistener mismatch:registerTaskEventListenerswiresTASK_CONFERENCE_TRANSFERRED → refreshTaskList, buthandleTaskRemovecalls.off(TASK_CONFERENCE_TRANSFERRED, handleConferenceEnded)— listener never removed.
Parent: migration-overview.md