@@ -31,9 +31,19 @@ import {
3131 getDefaultUIControls ,
3232 haveUIControlsChanged ,
3333} from './state-machine/uiControlsComputer' ;
34+ import type { TaskActionsMap } from './state-machine/actions' ;
3435
3536type CallId = string ;
3637
38+ export interface TaskActionCallbacks {
39+ onTaskHydrated ?: ( task : ITask , taskData : TaskData ) => void ;
40+ onTaskOffered ?: ( task : ITask , taskData : TaskData ) => void ;
41+ }
42+
43+ export interface TaskRuntimeOptions {
44+ actionCallbacks ?: TaskActionCallbacks ;
45+ }
46+
3747export default abstract class Task extends EventEmitter implements ITask {
3848 protected contact : ReturnType < typeof routingContact > ;
3949 protected metricsManager : MetricsManager ;
@@ -44,16 +54,19 @@ export default abstract class Task extends EventEmitter implements ITask {
4454 private lastState ?: TaskState ;
4555 protected currentUiControls : TaskUIControls ;
4656 protected uiControlConfig : UIControlConfig ;
57+ protected actionCallbacks ?: TaskActionCallbacks ;
4758
4859 constructor (
4960 contact : ReturnType < typeof routingContact > ,
5061 data : TaskData ,
51- uiControlConfig : UIControlConfig
62+ uiControlConfig : UIControlConfig ,
63+ runtimeOptions : TaskRuntimeOptions = { }
5264 ) {
5365 super ( ) ;
5466 this . contact = contact ;
5567 this . data = data ;
5668 this . uiControlConfig = uiControlConfig ;
69+ this . actionCallbacks = runtimeOptions . actionCallbacks ;
5770 this . metricsManager = MetricsManager . getInstance ( ) ;
5871 this . webCallMap = { } ;
5972 this . currentUiControls = getDefaultUIControls ( ) ;
@@ -167,7 +180,9 @@ export default abstract class Task extends EventEmitter implements ITask {
167180 * Initialize the state machine
168181 */
169182 private initializeStateMachine ( ) : void {
170- const machine : TaskStateMachine = createTaskStateMachine ( this . uiControlConfig ) ;
183+ const machine : TaskStateMachine = createTaskStateMachine ( this . uiControlConfig , {
184+ actions : this . getStateMachineActionOverrides ( ) ,
185+ } ) ;
171186
172187 this . stateMachineService = createActor ( machine ) ;
173188
@@ -233,6 +248,119 @@ export default abstract class Task extends EventEmitter implements ITask {
233248 }
234249 }
235250
251+ private extractTaskDataFromEvent ( event ?: TaskEventPayload ) : TaskData | undefined {
252+ if ( ! event || typeof event !== 'object' ) {
253+ return undefined ;
254+ }
255+
256+ if ( 'taskData' in event ) {
257+ return ( event as { taskData ?: TaskData } ) . taskData ;
258+ }
259+
260+ return undefined ;
261+ }
262+
263+ private updateTaskFromEvent ( event ?: TaskEventPayload ) : void {
264+ const taskData = this . extractTaskDataFromEvent ( event ) ;
265+ if ( taskData ) {
266+ this . updateTaskData ( taskData ) ;
267+ }
268+ }
269+
270+ protected getStateMachineActionOverrides ( ) : Partial < TaskActionsMap > {
271+ return {
272+ ...this . getCommonActionOverrides ( ) ,
273+ ...this . getChannelSpecificActionOverrides ( ) ,
274+ } ;
275+ }
276+
277+ protected getChannelSpecificActionOverrides ( ) : Partial < TaskActionsMap > {
278+ return { } ;
279+ }
280+
281+ protected createEmitSelfAction (
282+ taskEvent : TASK_EVENTS ,
283+ { updateTaskData = false } : { updateTaskData ?: boolean } = { }
284+ ) {
285+ return ( { event} : { event : TaskEventPayload } ) => {
286+ if ( updateTaskData ) {
287+ this . updateTaskFromEvent ( event ) ;
288+ }
289+ this . emit ( taskEvent , this ) ;
290+ } ;
291+ }
292+
293+ private getCommonActionOverrides ( ) : Partial < TaskActionsMap > {
294+ return {
295+ emitTaskHydrate : ( { event} : { event : TaskEventPayload } ) => {
296+ const taskData = this . extractTaskDataFromEvent ( event ) ;
297+ if ( ! taskData ) {
298+ return ;
299+ }
300+ if ( this . actionCallbacks ?. onTaskHydrated ) {
301+ this . actionCallbacks . onTaskHydrated ( this , taskData ) ;
302+ } else {
303+ this . updateTaskData ( taskData ) ;
304+ this . emit ( TASK_EVENTS . TASK_HYDRATE , this ) ;
305+ }
306+ } ,
307+ emitTaskOfferContact : ( { event} : { event : TaskEventPayload } ) => {
308+ const taskData = this . extractTaskDataFromEvent ( event ) ;
309+ if ( ! taskData ) {
310+ return ;
311+ }
312+ if ( this . actionCallbacks ?. onTaskOffered ) {
313+ this . actionCallbacks . onTaskOffered ( this , taskData ) ;
314+ } else {
315+ this . updateTaskData ( taskData ) ;
316+ this . emit ( TASK_EVENTS . TASK_OFFER_CONTACT , this ) ;
317+ }
318+ } ,
319+ emitTaskAssigned : this . createEmitSelfAction ( TASK_EVENTS . TASK_ASSIGNED , {
320+ updateTaskData : true ,
321+ } ) ,
322+ emitTaskEnd : this . createEmitSelfAction ( TASK_EVENTS . TASK_END , { updateTaskData : true } ) ,
323+ emitTaskOfferConsult : this . createEmitSelfAction ( TASK_EVENTS . TASK_OFFER_CONSULT , {
324+ updateTaskData : true ,
325+ } ) ,
326+ emitTaskConsultCreated : this . createEmitSelfAction ( TASK_EVENTS . TASK_CONSULT_CREATED , {
327+ updateTaskData : true ,
328+ } ) ,
329+ emitTaskConsulting : ( { event} : { event : TaskEventPayload } ) => {
330+ this . updateTaskFromEvent ( event ) ;
331+ if ( this . data . isConsulted ) {
332+ this . emit ( TASK_EVENTS . TASK_CONSULT_ACCEPTED , this ) ;
333+ } else {
334+ this . emit ( TASK_EVENTS . TASK_CONSULTING , this ) ;
335+ }
336+ } ,
337+ emitTaskConsultAccepted : this . createEmitSelfAction ( TASK_EVENTS . TASK_CONSULT_ACCEPTED ) ,
338+ emitTaskConsultEnd : this . createEmitSelfAction ( TASK_EVENTS . TASK_CONSULT_END , {
339+ updateTaskData : true ,
340+ } ) ,
341+ emitTaskConsultQueueCancelled : this . createEmitSelfAction (
342+ TASK_EVENTS . TASK_CONSULT_QUEUE_CANCELLED ,
343+ {
344+ updateTaskData : true ,
345+ }
346+ ) ,
347+ emitTaskConsultQueueFailed : this . createEmitSelfAction ( TASK_EVENTS . TASK_CONSULT_QUEUE_FAILED , {
348+ updateTaskData : true ,
349+ } ) ,
350+ emitTaskReject : ( { event} : { event : TaskEventPayload } ) => {
351+ this . updateTaskFromEvent ( event ) ;
352+ const reason =
353+ event && typeof event === 'object' && 'reason' in event
354+ ? ( event as { reason ?: string } ) . reason
355+ : undefined ;
356+ this . emit ( TASK_EVENTS . TASK_REJECT , reason ) ;
357+ } ,
358+ emitTaskWrappedup : this . createEmitSelfAction ( TASK_EVENTS . TASK_WRAPPEDUP , {
359+ updateTaskData : true ,
360+ } ) ,
361+ } ;
362+ }
363+
236364 private reconcileData ( oldData : TaskData , newData : TaskData ) : TaskData {
237365 Object . keys ( newData ) . forEach ( ( key ) => {
238366 if ( newData [ key ] && typeof newData [ key ] === 'object' && ! Array . isArray ( newData [ key ] ) ) {
0 commit comments