WxCC Widgets
References
My Widgets
Headless Social Auto Answer Widget
This was based on the headless sample provided by Cisco. Most of the code was then removed and then new code was added which uses the Agent Contact Module.
When this headless gadget is added to the Agent's desktop layout - any incoming Social Tasks (e.g. WhatsApp) will get accepted automatically (i.e. enable auto answer for social chats).
Headless Social Auto Answer Package
Package: headless-social-autoanswer-widget.zip
- download above and to run locally (http://localhost:5000/build/bundle.js) then run the following (from the project directory):
- npm install
- npm run build
- npm run dev
If you then want to host the file - copy the ./srv/build/bundle.js file and place it on a public facing web server (and update your Desktop Layout with the new URL) - an example Desktop layout for this headless widget is below.
- headless-widget-social-autoanswer.js
import { Desktop } from '@wxcc-desktop/sdk'; // This is the logger initializer factory method for the headless widget export const logger = Desktop.logger.createLogger('headless-social-autoanswer-widget'); // Some sample data points let version = 1.00; customElements.define( 'headless-social-autoanswer-widget', class extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } // Mounting the headless widget and initializing async connectedCallback() { logger.info('Log: Version: ' + version); this.init(); logger.info('Log: Webcomponent connectedCallback function'); } // Init Method - called to configure the WebexCC Desktop JS SDK inside the headless widget async init() { await Desktop.config.init(); logger.info('Log: init function'); this.registerEventListeners(); } // This method registers all the event listeners supported by the JS SDK. // The event listeners are asynchronous and require handlers within each of the listeners. // Sample handlers below are only console logs as examples async registerEventListeners() { // Listener for agent contact offered event - Customized by GOR Desktop.agentContact.addEventListener('eAgentOfferContact', async (agentContact) => { logger.info('Log: Agent Offered Contact'); //logger.info('Log: Agent Offered Contact: Details: '+ JSON.stringify(agentContact)); let callOfferedContactDirection = agentContact.data['interaction'].contactDirection.type; logger.info('Log: callOffered contactDirection: '+ callOfferedContactDirection); let callOfferedInteractionId = agentContact.data['interaction'].interactionId; logger.info('Log: callOfferedInteractionId: '+ callOfferedInteractionId); let callOfferedMediaType = agentContact.data['interaction'].mediaType; logger.info('Log: callOfferedMediaType: '+ callOfferedMediaType); if(callOfferedContactDirection.toLowerCase() === 'inbound' && callOfferedMediaType.toLowerCase() === 'social'){ logger.info('Log: Incoming Social Task Offered. Let\'s attempt to Auto Answer!'); let acceptContactResponse = await Desktop.agentContact.accept({interactionId: callOfferedInteractionId}); //logger.info('Log: acceptContactResponse: '+ JSON.stringify(acceptContactResponse)); try{ let acceptContactResponseInteractionState = acceptContactResponse.data['interaction'].state; //logger.info('Log: acceptResponseInteractionState: '+ acceptContactResponseInteractionState); if (acceptContactResponseInteractionState === "connected"){ logger.info('Log: Accepted Task Successfully. Now connected.'); }else{ logger.info('Log: Failed to Accept task? acceptResponseInteractionState: '+ acceptContactResponseInteractionState); } } catch(error){ logger.info('Log: acceptResponseInteractionState - error:'+ error); } } }); } disconnectedCallback() {;} });
Desktop Layout Code snippet
"headless": { "id": "dw-headless", "widgets": { "comp1": { "comp": "headless-social-autoanswer-widget", "script": "http://localhost:5000/build/bundle.js" } }, "layout": { "areas": [ [ "comp1" ] ], "size": { "cols": [ 1 ], "rows": [ 1 ] } } }
Console Logs
Change RONA V2
This Widget is based on Aashish Berry change-rona widget which is located here:
It has 2 enhancements over the original.
- It stops double initialization - which seems to happen in WxCC gadgets? (when you press f5 and look at the console logs - it often get double logs)
connectedCallback() { if (initialized) return; // stop double initialization of Widget this.init(); initialized = true; }
- The original version attempted to make the agent available after the delaySeconds timer expires - no matter what. i.e. Even if in the mean time, the agent have moved from RONA and back into Idle with manual code. This is not what users would want. This is now prevented by checking, just before moving the agent into available, that the current state is indeed still Idle RONA. Only if its Idle due to RONA will it attempt move the agent back to an Available state.
- Note - As the user logs in the widget the widget loads, it then pauses for 15 seconds before loading the rest of the code. If the agent has NOT completed login by this time (i.e. if the user does not complete login by confirming their team / extension), the events to catch the RONA events do not trigger and the gadget does not work as intended.
Package: change-rona_20260226.7z
- download above and to run locally (http://localhost:3001/build/change-rona.js) then run the following (from the project directory):
- npm install
- npm run build
- npm run dev
- change-rona.js
/* /* Update on Sample Gadget provided by Aashish Berry (aaberry) - https://github.com/aashishberry/desktopWidgets/tree/main This version checks BEFORE attempting to make the agent available that the agent state is Idel with Idle Code of 'RONA' Only then will it allow the agent state to move back to available. This allows an agent to go Idle with different reason code (manually) and the widget will NOT pushed the agent back into available automatically It also not allow the gadget to attempt to move the agent into available again even if the agent is already available! */ import { Desktop } from '@wxcc-desktop/sdk'; const logger = Desktop.logger.createLogger('change-ronaV2'); logger.info('Change RONA Widget Loading...'); let initialized = false; class changeRona extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); } connectedCallback() { if (initialized) return; // stop double initialization of Widget this.init(); initialized = true; } disconnectedCallback() { Desktop.agentContact.removeAllEventListeners(); Desktop.agentStateInfo.removeAllEventListeners(); } sleep = (delay) => new Promise(r => setTimeout(r, delay)); async init() { logger.info('init(): Waiting 15 Seconds, the agent needs to complete login within this time for this gadget to work. Otherwise RONA Event Listner does not trigger (I do not know why?)'); await this.sleep(15000); await Desktop.config.init({ widgetName: "change-ronaV2", widgetProvider: "GOR" }); if (this.delaySeconds) { logger.info('Delay read from layout: ' + this.delaySeconds + ' seconds.'); this.delaySeconds = this.delaySeconds * 1000; } else { this.delaySeconds = 10000; logger.info('Delay unavailable in layout. Default 10 seconds.'); } logger.info("Widget initialized"); this.agentInteractionEvents(); } async agentInteractionEvents() { //logger.info(Desktop.agentStateInfo.latestData); Desktop.agentContact.addEventListener("eAgentOfferContactRona", () => { logger.info('RONA triggered - lets sleep for ' + this.delaySeconds/1000 + ' seconds before we attempt to move the agent back into Available state'); this.triggerChange(); }); } async triggerChange() { await this.sleep(this.delaySeconds); logger.info("Our RONA sleep timer has completed."); if (Desktop.agentStateInfo.latestData.idleCode.name === 'RONA'){ logger.info("Agent is in an idle state with an idleCode name of 'RONA', hence we will attempt to move back to Available..."); try { await Desktop.agentStateInfo.stateChange({ state: 'Available', auxCodeIdArray: '0', }); logger.info("Agent State changed to Available!"); } catch (e) { logger.error(e); } }else{ logger.info("Agent is no longer in an idle state so we will NOT attempt to move back to Available..."); } } } window.customElements.define("change-rona", changeRona);
