Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Control Worker Activities using Worker.js: Add an Agent UI to our Project


Let's get started on our agent UI. Assuming you've followed the conventions so far in this tutorial, the UI we create will be accessible using your web browser at:

http://localhost:8080/agent.cshtml?WorkerSid=WK01234012340123401234 (substitute your Alice's WorkerSid)

We pass the WorkerSid in the URL to avoid implementing complex user management in our demo. In reality, you are likely to store a user's WorkerSid in your database alongside other User attributes.

Now create a CSHTML file that will be rendered when the URL is requested:


agent.cshtml

agentcshtml page anchor

_219
@using System;
_219
@using System.Collections.Generic;
_219
@using Twilio;
_219
@using Twilio.Http;
_219
@using Twilio.Jwt.Taskrouter;
_219
_219
@{
_219
class PolicyUrlUtils
_219
{
_219
const string taskRouterBaseUrl = "https://taskrouter.twilio.com";
_219
const string taskRouterVersion = "v1";
_219
_219
readonly string _workspaceSid;
_219
readonly string _workerSid;
_219
_219
public PolicyUrlUtils(string workspaceSid, string workerSid)
_219
{
_219
_workspaceSid = workspaceSid;
_219
_workerSid = workerSid;
_219
}
_219
_219
public string AllTasks => $"{Workspace}/Tasks/**";
_219
_219
public string Worker => $"{Workspace}/Workers/{_workerSid}";
_219
_219
public string AllReservations => $"{Worker}/Reservations/**";
_219
_219
public string Workspace =>
_219
$"{taskRouterBaseUrl}/{taskRouterVersion}/Workspaces/{_workspaceSid}";
_219
_219
public string Activities => $"{Workspace}/Activities";
_219
_219
}
_219
_219
@{
_219
// put your Twilio API credentials here
_219
const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
_219
const string authToken = "your_auth_token";
_219
const string workspaceSid = "WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
_219
const string workerSid = "WKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
_219
_219
var updateActivityFilter = new Dictionary<string, Policy.FilterRequirement>
_219
{
_219
{ "ActivitySid", Policy.FilterRequirement.Required }
_219
};
_219
_219
var urls = new PolicyUrlUtils(workspaceSid, workerSid);
_219
_219
var allowActivityUpdates = new Policy(urls.Worker,
_219
HttpMethod.Post,
_219
postFilter: updateActivityFilter);
_219
var allowTasksUpdate = new Policy(urls.AllTasks, HttpMethod.Post);
_219
var allowReservationUpdate = new Policy(urls.AllReservations, HttpMethod.Post);
_219
var allowWorkerFetches = new Policy(urls.Worker, HttpMethod.Get);
_219
var allowTasksFetches = new Policy(urls.AllTasks, HttpMethod.Get );
_219
var allowReservationFetches = new Policy(urls.AllReservations, HttpMethod.Get);
_219
var allowActivityFetches = new Policy(urls.Activities, HttpMethod.Get);
_219
_219
var policies = new List<Policy>
_219
{
_219
allowActivityUpdates,
_219
allowTasksUpdate,
_219
allowReservationUpdate,
_219
allowWorkerFetches,
_219
allowTasksFetches,
_219
allowReservationFetches
_219
_219
};
_219
_219
var capability = new TaskRouterCapability(
_219
accountSid,
_219
authToken,
_219
workspaceSid,
_219
workerSid,
_219
policies: policies);
_219
_219
var workerToken = capability.ToJwt();
_219
}
_219
<!DOCTYPE html>
_219
<html>
_219
<head>
_219
<title>Customer Care - Voice Agent Screen</title>
_219
<link rel="stylesheet" href="//media.twiliocdn.com/taskrouter/quickstart/agent.css"/>
_219
<script src="https://sdk.twilio.com/js/taskrouter/v1.21/taskrouter.min.js" integrity="sha384-5fq+0qjayReAreRyHy38VpD3Gr9R2OYIzonwIkoGI4M9dhfKW6RWeRnZjfwSrpN8" crossorigin="anonymous"></script>
_219
<script type="text/javascript">
_219
/* Subscribe to a subset of the available TaskRouter.js events for a worker */
_219
function registerTaskRouterCallbacks() {
_219
worker.on('ready', function(worker) {
_219
agentActivityChanged(worker.activityName);
_219
logger("Successfully registered as: " + worker.friendlyName)
_219
logger("Current activity is: " + worker.activityName);
_219
});
_219
_219
worker.on('activity.update', function(worker) {
_219
agentActivityChanged(worker.activityName);
_219
logger("Worker activity changed to: " + worker.activityName);
_219
});
_219
_219
worker.on("reservation.created", function(reservation) {
_219
logger("-----");
_219
logger("You have been reserved to handle a call!");
_219
logger("Call from: " + reservation.task.attributes.from);
_219
logger("Selected language: " + reservation.task.attributes.selected_language);
_219
logger("-----");
_219
});
_219
_219
worker.on("reservation.accepted", function(reservation) {
_219
logger("Reservation " + reservation.sid + " accepted!");
_219
});
_219
_219
worker.on("reservation.rejected", function(reservation) {
_219
logger("Reservation " + reservation.sid + " rejected!");
_219
});
_219
_219
worker.on("reservation.timeout", function(reservation) {
_219
logger("Reservation " + reservation.sid + " timed out!");
_219
});
_219
_219
worker.on("reservation.canceled", function(reservation) {
_219
logger("Reservation " + reservation.sid + " canceled!");
_219
});
_219
}
_219
_219
/* Hook up the agent Activity buttons to TaskRouter.js */
_219
_219
function bindAgentActivityButtons() {
_219
// Fetch the full list of available Activities from TaskRouter. Store each
_219
// ActivitySid against the matching Friendly Name
_219
var activitySids = {};
_219
worker.activities.fetch(function(error, activityList) {
_219
var activities = activityList.data;
_219
var i = activities.length;
_219
while (i--) {
_219
activitySids[activities[i].friendlyName] = activities[i].sid;
_219
}
_219
});
_219
_219
/* For each button of class 'change-activity' in our Agent UI, look up the
_219
ActivitySid corresponding to the Friendly Name in the button's next-activity
_219
data attribute. Use Worker.js to transition the agent to that ActivitySid
_219
when the button is clicked.*/
_219
var elements = document.getElementsByClassName('change-activity');
_219
var i = elements.length;
_219
while (i--) {
_219
elements[i].onclick = function() {
_219
var nextActivity = this.dataset.nextActivity;
_219
var nextActivitySid = activitySids[nextActivity];
_219
worker.update({"ActivitySid":nextActivitySid});
_219
}
_219
}
_219
}
_219
_219
/* Update the UI to reflect a change in Activity */
_219
_219
function agentActivityChanged(activity) {
_219
hideAgentActivities();
_219
showAgentActivity(activity);
_219
}
_219
_219
function hideAgentActivities() {
_219
var elements = document.getElementsByClassName('agent-activity');
_219
var i = elements.length;
_219
while (i--) {
_219
elements[i].style.display = 'none';
_219
}
_219
}
_219
_219
function showAgentActivity(activity) {
_219
activity = activity.toLowerCase();
_219
var elements = document.getElementsByClassName(('agent-activity ' + activity));
_219
elements.item(0).style.display = 'block';
_219
}
_219
_219
/* Other stuff */
_219
_219
function logger(message) {
_219
var log = document.getElementById('log');
_219
log.value += "\n> " + message;
_219
log.scrollTop = log.scrollHeight;
_219
}
_219
_219
window.onload = function() {
_219
// Initialize TaskRouter.js on page load using window.workerToken -
_219
// a Twilio Capability token that was set from rendering the template with agents endpoint
_219
logger("Initializing...");
_219
window.worker = new Twilio.TaskRouter.Worker("@workerToken");
_219
_219
registerTaskRouterCallbacks();
_219
bindAgentActivityButtons();
_219
};
_219
</script>
_219
</head>
_219
<body>
_219
<div class="content">
_219
<section class="agent-activity offline">
_219
<p class="activity">Offline</p>
_219
<button class="change-activity" data-next-activity="Idle">Go Available</button>
_219
</section>
_219
<section class="agent-activity idle">
_219
<p class="activity"><span>Available</span></p>
_219
<button class="change-activity" data-next-activity="Offline">Go Offline</button>
_219
</section>
_219
<section class="agent-activity reserved">
_219
<p class="activity">Reserved</p>
_219
</section>
_219
<section class="agent-activity busy">
_219
<p class="activity">Busy</p>
_219
</section>
_219
<section class="agent-activity wrapup">
_219
<p class="activity">Wrap-Up</p>
_219
<button class="change-activity" data-next-activity="Idle">Go Available</button>
_219
<button class="change-activity" data-next-activity="Offline">Go Offline</button>
_219
</section>
_219
<section class="log">
_219
<textarea id="log" readonly="true"></textarea>
_219
</section>
_219
</div>
_219
</body>
_219
</html>

You'll notice that we included two external files:

  • taskrouter.min.js is the primary TaskRouter.js JavaScript file that communicates with TaskRouter's infrastructure on our behalf. You can use this URL to include Worker.js in your production application, but first check the reference documentation to ensure that you include the latest version number.
  • agent.css is a simple CSS file created for the purpose of this Quickstart. It saves us having to type out some simple pre-defined styles.

And that's it! Compile your Java class and start your server.

Open http://localhost:8080/agent.cshtml?WorkerSid=WK01234012340123401234 in your browser and you should see the screen below. If you make the same phone call as we made in Part 3, you should see Alice's Activity transition on screen as she is reserved and assigned to handle the Task.

If you see "Initializing..." and no progress, make sure that you have included the correct WorkerSid in the "WorkerSid" request parameter of the URL.

For more details, refer to the TaskRouter JavaScript SDK documentation.


  • This simple PoC has been tested in the latest version of popular browsers, including IE 11. *
Completed Agent UI.

Rate this page: