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.php?WorkerSid=WKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
(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.
First, create a file called agent.php
and add the following code. Remember to substitute your own account and Workspace credentials between the curly braces:
_58<?php_58// Get the Twilio-PHP library from twilio.com/docs/libraries/php, _58// following the instructions to install it with Composer._58require_once "vendor/autoload.php";_58_58// Your Account SID from www.twilio.com/console_58// To set up environmental variables, see http://twil.io/secure_58$accountSid = getenv('TWILIO_ACCOUNT_SID');_58// Your Auth Token from www.twilio.com/console_58$authToken = getenv('TWILIO_AUTH_TOKEN');_58$workspaceSid = 'WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; _58_58$workerSid = $_REQUEST['WorkerSid'];_58_58$workerCapability = new Twilio\Jwt\TaskRouter\WorkerCapability(_58 $accountSid, $authToken, $workspaceSid, $workerSid);_58$workerCapability->allowActivityUpdates();_58$workerToken = $workerCapability->generateToken();_58_58?>_58<!DOCTYPE html>_58<html>_58<head>_58 <title>Customer Care - Voice Agent Screen</title>_58 <link rel="stylesheet" href="//media.twiliocdn.com/taskrouter/quickstart/agent.css"/>_58 <script src="//media.twiliocdn.com/taskrouter/js/v1.13/taskrouter.min.js"></script>_58 <script src="agent.js"></script>_58</head>_58<body>_58<div class="content">_58 <section class="agent-activity offline">_58 <p class="activity">Offline</p>_58 <button class="change-activity" data-next-activity="Idle">Go Available</button>_58 </section>_58 <section class="agent-activity idle">_58 <p class="activity"><span>Available</span></p>_58 <button class="change-activity" data-next-activity="Offline">Go Offline</button>_58 </section>_58 <section class="agent-activity reserved">_58 <p class="activity">Reserved</p>_58 </section>_58 <section class="agent-activity busy">_58 <p class="activity">Busy</p>_58 </section>_58 <section class="agent-activity wrapup">_58 <p class="activity">Wrap-Up</p>_58 <button class="change-activity" data-next-activity="Idle">Go Available</button>_58 <button class="change-activity" data-next-activity="Offline">Go Offline</button>_58 </section>_58 <section class="log">_58 <textarea id="log" readonly="true"></textarea>_58 </section>_58</div>_58<script>_58 window.workerToken = "<?= $workerToken ?>";_58</script>_58</body>_58</html>
You'll notice that we included three external files:
Download and extract Twilio's PHP helper library into the same directory that you are working in. This is required as our code references twilio-php/Services/Twilio.php
. For more advanced PHP users, the composer package manager will also work fine. See the twilio-php documentation.
Create the agent.js file in the same directory as your agent.php and add the following code:
_105/* Subscribe to a subset of the available Worker.js events */_105_105function registerTaskRouterCallbacks() {_105 worker.on('ready', function(worker) {_105 agentActivityChanged(worker.activityName);_105 logger("Successfully registered as: " + worker.friendlyName)_105 logger("Current activity is: " + worker.activityName);_105 });_105_105 worker.on('activity.update', function(worker) {_105 agentActivityChanged(worker.activityName);_105 logger("Worker activity changed to: " + worker.activityName);_105 });_105_105 worker.on("reservation.created", function(reservation) {_105 logger("-----");_105 logger("You have been reserved to handle a call!");_105 logger("Call from: " + reservation.task.attributes.from);_105 logger("Selected language: " + reservation.task.attributes.selected_language);_105 logger("-----");_105 });_105_105 worker.on("reservation.accepted", function(reservation) {_105 logger("Reservation " + reservation.sid + " accepted!");_105 });_105_105 worker.on("reservation.rejected", function(reservation) {_105 logger("Reservation " + reservation.sid + " rejected!");_105 });_105_105 worker.on("reservation.timeout", function(reservation) {_105 logger("Reservation " + reservation.sid + " timed out!");_105 });_105_105 worker.on("reservation.canceled", function(reservation) {_105 logger("Reservation " + reservation.sid + " canceled!");_105 });_105}_105_105/* Hook up the agent Activity buttons to Worker.js */_105_105function bindAgentActivityButtons() {_105 // Fetch the full list of available Activities from TaskRouter. Store each_105 // ActivitySid against the matching Friendly Name_105 var activitySids = {};_105 worker.activities.fetch(function(error, activityList) {_105 var activities = activityList.data;_105 var i = activities.length;_105 while (i--) {_105 activitySids[activities[i].friendlyName] = activities[i].sid;_105 }_105 });_105_105 /* For each button of class 'change-activity' in our Agent UI, look up the_105 ActivitySid corresponding to the Friendly Name in the button's next-activity_105 data attribute. Use Worker.js to transition the agent to that ActivitySid_105 when the button is clicked.*/_105 var elements = document.getElementsByClassName('change-activity');_105 var i = elements.length;_105 while (i--) {_105 elements[i].onclick = function() {_105 var nextActivity = this.dataset.nextActivity;_105 var nextActivitySid = activitySids[nextActivity];_105 worker.update({"ActivitySid":nextActivitySid});_105 }_105 }_105}_105_105/* Update the UI to reflect a change in Activity */_105_105function agentActivityChanged(activity) {_105 hideAgentActivities();_105 showAgentActivity(activity);_105}_105_105function hideAgentActivities() {_105 var elements = document.getElementsByClassName('agent-activity');_105 var i = elements.length;_105 while (i--) {_105 elements[i].style.display = 'none';_105 }_105}_105_105function showAgentActivity(activity) {_105 activity = activity.toLowerCase();_105 var elements = document.getElementsByClassName(('agent-activity ' + activity));_105 elements.item(0).style.display = 'block';_105}_105_105/* Other stuff */_105_105function logger(message) {_105 var log = document.getElementById('log');_105 log.value += "\n> " + message;_105 log.scrollTop = log.scrollHeight;_105}_105_105window.onload = function() {_105 // Initialize TaskRouter.js on page load using window.workerToken -_105 // a Twilio Capability token that was set in a <script> in agent.php_105 logger("Initializing...");_105 window.worker = new Twilio.TaskRouter.Worker(workerToken);_105 registerTaskRouterCallbacks();_105 bindAgentActivityButtons();_105};
And that's it! Open http://localhost:8080/agent.php?WorkerSid=WK012340123401234
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.js Worker JavaScript SDK documentation.