-
Notifications
You must be signed in to change notification settings - Fork 65
fix(cc-task): fix hold/resume not working after recording pause/resume #667
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
c8c0a28
ae62a5c
28233f5
87e64aa
3bcf6af
8a0cc4b
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 |
|---|---|---|
|
|
@@ -297,6 +297,7 @@ | |
| agentId, | ||
| } = props; | ||
| const [isRecording, setIsRecording] = useState(true); | ||
| const [isHeld, setIsHeld] = useState(false); | ||
| const [buddyAgents, setBuddyAgents] = useState<BuddyDetails[]>([]); | ||
| const [loadingBuddyAgents, setLoadingBuddyAgents] = useState(false); | ||
| const [consultAgentName, setConsultAgentName] = useState<string>('Consult Agent'); | ||
|
|
@@ -445,6 +446,13 @@ | |
| } | ||
| }, [currentTask, logger, lastTargetType, consultAgentName, setConsultAgentName]); | ||
|
|
||
| // Sync local hold state from controlVisibilityBase only when a different task is selected | ||
| // (not on every currentTask reference change, which would overwrite event-driven state) | ||
| useEffect(() => { | ||
| setIsHeld(controlVisibilityBase?.isHeld ?? false); | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [currentTask?.data?.interactionId, agentId]); | ||
|
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 effect only depends on Useful? React with 👍 / 👎. |
||
|
|
||
| // Extract main call timestamp whenever currentTask changes | ||
| useEffect(() => { | ||
| extractConsultingAgent(); | ||
|
|
@@ -530,6 +538,7 @@ | |
|
|
||
| const holdCallback = () => { | ||
| try { | ||
| setIsHeld(true); | ||
| if (onHoldResume) { | ||
| onHoldResume({ | ||
| isHeld: true, | ||
|
|
@@ -546,6 +555,7 @@ | |
|
|
||
| const resumeCallback = () => { | ||
| try { | ||
| setIsHeld(false); | ||
| if (onHoldResume) { | ||
| onHoldResume({ | ||
| isHeld: false, | ||
|
|
@@ -595,10 +605,12 @@ | |
| const pauseRecordingCallback = () => { | ||
| try { | ||
| setIsRecording(false); | ||
| onRecordingToggle({ | ||
| isRecording: false, | ||
| task: currentTask, | ||
| }); | ||
| if (onRecordingToggle) { | ||
| onRecordingToggle({ | ||
| isRecording: false, | ||
| task: currentTask, | ||
| }); | ||
| } | ||
| } catch (error) { | ||
| logger?.error(`CC-Widgets: Task: Error in pauseRecordingCallback - ${error.message}`, { | ||
| module: 'useCallControl', | ||
|
|
@@ -610,10 +622,12 @@ | |
| const resumeRecordingCallback = () => { | ||
| try { | ||
| setIsRecording(true); | ||
| onRecordingToggle({ | ||
| isRecording: true, | ||
| task: currentTask, | ||
| }); | ||
| if (onRecordingToggle) { | ||
| onRecordingToggle({ | ||
| isRecording: true, | ||
| task: currentTask, | ||
| }); | ||
| } | ||
| } catch (error) { | ||
| logger?.error(`CC-Widgets: Task: Error in resumeRecordingCallback - ${error.message}`, { | ||
| module: 'useCallControl', | ||
|
|
@@ -648,8 +662,8 @@ | |
| store.removeTaskCallback(TASK_EVENTS.TASK_RESUME, resumeCallback, interactionId); | ||
| store.removeTaskCallback(TASK_EVENTS.TASK_END, endCallCallback, interactionId); | ||
| store.removeTaskCallback(TASK_EVENTS.AGENT_WRAPPEDUP, wrapupCallCallback, interactionId); | ||
| store.removeTaskCallback(TASK_EVENTS.CONTACT_RECORDING_PAUSED, pauseRecordingCallback, interactionId); | ||
| store.removeTaskCallback(TASK_EVENTS.CONTACT_RECORDING_RESUMED, resumeRecordingCallback, interactionId); | ||
| store.removeTaskCallback(TASK_EVENTS.TASK_RECORDING_PAUSED, pauseRecordingCallback, interactionId); | ||
| store.removeTaskCallback(TASK_EVENTS.TASK_RECORDING_RESUMED, resumeRecordingCallback, interactionId); | ||
| }; | ||
| }, [currentTask]); | ||
|
|
||
|
|
@@ -927,11 +941,14 @@ | |
| currentTask.cancelAutoWrapupTimer(); | ||
| }; | ||
|
|
||
| const controlVisibility = useMemo( | ||
| const controlVisibilityBase = useMemo( | ||
| () => getControlsVisibility(deviceType, featureFlags, currentTask, agentId, conferenceEnabled, logger), | ||
| [deviceType, featureFlags, currentTask, agentId, conferenceEnabled, logger] | ||
| ); | ||
|
|
||
| // Override isHeld with event-driven local state to avoid stale task data from getAllTasks() | ||
| const controlVisibility = useMemo(() => ({...controlVisibilityBase, isHeld}), [controlVisibilityBase, isHeld]); | ||
|
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.
Overriding only Useful? React with 👍 / 👎. 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.
Overriding only Useful? React with 👍 / 👎. 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 new Useful? React with 👍 / 👎. |
||
|
|
||
| // Add useEffect for auto wrap-up timer | ||
| useEffect(() => { | ||
| let timerId: NodeJS.Timeout; | ||
|
|
||
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.
The new hold sync effect only depends on
currentTask?.data?.interactionId, so it runs once per interaction and never retries when the same interaction is refreshed with newer data. In the exact incomplete-payload case this block already anticipates (thefindHoldStatustry/catch), a laterrefreshTaskListupdate for the same interaction ID will not re-syncisHeld, and the stale local value will keep overridinggetControlsVisibility. Please include hold-relevant task data (orcurrentTask) in the dependencies so local state can recover when the task object is hydrated.Useful? React with 👍 / 👎.
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.
Intentionally keeping
interactionIdas the dependency rather thancurrentTask. The root cause of this bug is that the SDK fires TASK_HOLD/TASK_RESUME events before updating its internal task data, sorefreshTaskList→getAllTasks()returns staleisHold: false. AddingcurrentTaskback to the deps would re-run the sync on everyrefreshTaskListand overwrite the event-driven state — reintroducing the original bug. The event callbacks (holdCallback/resumeCallback) are the source of truth during a call; this effect only seeds the initial value on task switch.