© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2021
R. StringerReal-Time Twilio and Flybasehttps://doi.org/10.1007/978-1-4842-7074-5_7

7. Building a Real-Time Call Tracking Dashboard

Roger Stringer1  
(1)
Penticton, BC, Canada
 

This chapter will show you how to implement a real-time call tracking dashboard.

We’ll do this in two parts: the first part will be a simple Node.js file that accepts incoming calls from Twilio and then stores the information inside a Flybase app, and the second part is the dashboard itself.

We’re going to display two stats, the incoming Twilio phone number and the city the call originated from. You can build on this further later.

With our original dashboard, we passed events and didn’t actually store any information. This time we’ll be storing the information to retrieve later.

The Backend

Let’s build the backend section of your dashboard.

First, let’s set up our “package.json” file:
{
  "name": "call-tracking",
  "version": "1.0.0",
  "description": "Example app demonstrating how to do call tracking with Twilio and Flybase",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/flybaseio/call-tracking.git"
  },
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/flybaseio/call-tracking/issues"
  },
  "homepage": "https://github.com/flybaseio/call-tracking#readme",
  "dependencies": {
    "body-parser": "^1.15.2",
    "compression": "^1.6.2",
    "cors": "^2.8.1",
    "ejs": "^2.5.2",
    "express": "^4.14.0",
    "flybase": "^1.7.8",
    "method-override": "^2.3.6",
    "serve-static": "^1.11.1"
  }
}
Now, let’s set up our “index.js” file to run as our backend:
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
var flybase = require('flybase');
var path = require('path');
var cors = require('cors');
var compression = require('compression');
var serveStatic = require('serve-static');
var app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({     extended: true     }));
app.use(express.static( path.join(__dirname, 'public')));
var port = process.env.PORT || 5000; // set our port
var flybaseRef = flybase.init('YOUR-FLYBASE-APP-NAME', "calltracking", 'YOUR-FLYBASE-API-KEY');
//     backend
app.post('/call', function(req, res) {
     flybaseRef.push({
          time: Date.now()/1000,
          number: req.body.To,
          city: req.body.FromCity
     }).then( function( rec ){
          res.type('text/xml');
          res.render('twiml', { message: 'Your call has been recorded!' })
     }, function(err){
          res.type('text/xml');
          console.log(error);
          res.render('twiml', { message: 'Sorry, an error happened.' });
     });
});
Now, let’s add the frontend handler. This will just be part of the same “index.js” file:
```javascript
// frontend
function setCustomCacheControl(res, path) {
     if (serveStatic.mime.lookup(path) === 'text/html') {
          // Custom Cache-Control for HTML files
          res.setHeader('Cache-Control', 'public, max-age=0')
     }
}
app.use(compression());
app.use(serveStatic(__dirname + '/dashboard', {
     maxAge: '1d',
     setHeaders: setCustomCacheControl,
     'index': ['index.html'],
     fallthrough: true
}));
var server = http.createServer(app);
server.listen(process.env.PORT || 3000, function() {
     console.log('Express server started.');
});
```

I’m using the serve-static module here since the dashboard can be stand-alone if we want it to be, so it’s just your standard HTML page served statically, so we’ll tell our app to display any file inside the dashboard folder.

Finally, we need to create a folder called views and add a tiny little file called twiml.ejs:
<Response>
     <Say><%= message %></Say>
</Response>

This is used to return our TwiML (Twilio Markup Language) response on incoming calls. You can play with this further to make it do things like connect a call to another number and so on, but for this app, we just need to record and track.

The Frontend

We want this dashboard to be able to run anywhere, so we’re just going to include the dashboard folder and set up our Node app to serve it statically. You can actually upload the dashboard folder anywhere you want and have it run and display your call tracking stats.

Create a folder called dashboard. Now, create a file inside the dashboard folder called index.html:
<!doctype html>
<html>
     <head>
          <title>Call Tracking On the Fly</title>
          <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha256-7s5uDGW3AHqw6xtJmNNtr+OBRJUlgkNJEo78P4b0yRw= sha512-nNo+yCHEyn0smMxSswnf/OnX6/KwJuZTlNZBjauKhTK0c+zT+q5JOCx0UFhXQ6rJR9jg6Es8gPuD2uZcYDLqSw==" crossorigin="anonymous">
          <link href="https://cdnjs.cloudflare.com/ajax/libs/epoch/0.5.2/epoch.min.css" rel="stylesheet" />
          <link href="dashboard.css" rel="stylesheet" />
     </head>
     <body>
          <div class="navbar-nav navbar-inverse navbar-fixed-top">
                    <div class="container">
                    <div class="navbar-header">
                         <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                              <span class="icon-bar"></span>
                              <span class="icon-bar"></span>
                              <span class="icon-bar"></span>
                         </button>
                         <a class="navbar-brand" href="index.html">
                              Call Tracking Dashboard
                         </a>
                    </div>
                         <div class="navbar-collapse collapse">
                              <ul class="nav navbar-nav">
                                   <li class="active">
                                        <!-- <a href="index.html">
                                             <i class="icon-home icon-white"></i> Home
                                        </a> -->
                                   </li>
                              </ul>
                         </div><!--/.nav-collapse -->
                    </div>
          </div>
          <div class="container">
               <div class="row">
                    <div class="col-sm-12 col-lg-12">
                         <article class="widget">
                              <div class="widget-inner">
                                   <header>
                                        <h1>Calls</h1>
                                   </header>
                                   <section class="widget-body">
                                        <div id="calls" class="epoch" style="height: 200px;"></div>
                                   </section>
                              </div><!-- .widget-inner -->
                         </article>
                    </div>
               </div>
               <div class="row">
                    <div class="col-sm-6 col-lg-6">
                         <article class="widget">
                              <div class="widget-inner">
                                   <header>
                                        <h1>Incoming Number</h1>
                                   </header>
                                   <section class="widget-body">
                                        <div id="numbers" class="epoch" style="height: 200px;"></div>
                                   </section>
                              </div><!-- .widget-inner -->
                         </article>
                    </div>
                    <div class="col-sm-6 col-lg-6">
                         <article class="widget">
                              <div class="widget-inner">
                                   <header>
                                        <h1>City</h1>
                                   </header>
                                   <section class="widget-body">
                                        <div id="cities" class="epoch" style="height: 200px;"></div>
                                   </section>
                              </div><!-- .widget-inner -->
                         </article>
                    </div>
               </div>
          </div>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.10/d3.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/epoch/0.5.2/epoch.min.js"></script>
     <script src="https://cdn.flybase.io/flybase.js"></script>
     <script src="dashboard.js"></script>
</body>
</html>
You will next create a file called dashboard.js:
$( function() {
     var calls = $('#calls').epoch( {
          type: 'time.area', axes: ['left', 'bottom', 'right'],
          data: [ { values: [ { time: Date.now()/1000, y: 0 } ] } ]
     } );
     var numbers = $( '#numbers' ).epoch( { type: 'bar' } );
     var cities = $( '#cities' ).epoch( { type: 'bar' } );
     var stats = {
          cities: {},
          numbers: {}
     };
     var dashboard = new Flybase("YOUR-FLYBASE-API-KEY", "calltracking", "stats");
     dashboard.once('value', function (data) {
          updateStats( data );
     });
     dashboard.on( 'added', function (data ){
          updateStats( data );
     });
     function updateStats( data ){
          //     process the new data...
          data.forEach( function( snapshot ){
               var row = snapshot.value();
               calls.push( [ { time: row.time, y: 1 } ] );
               var cityCount = stats.cities[ row.city ] || 0;
               stats.cities[ row.city ] = ++cityCount;
               var numberCount = stats.numbers[ row.number ] || 0;
               stats.numbers[ row.number ] = ++numberCount;
          });
          var citiesData = [];
          for( var city in stats.cities ) {
               citiesData.push( { x: city, y: stats.cities[ city ] } );
          }
          cities.update( [ { values: citiesData } ] );
          var numbersData = [];
          for( var number in stats.numbers ) {
               numbersData.push( { x: number, y: stats.numbers[ number ] } );
          }
          numbers.update( [ { values: numbersData } ] );
     }
});

This is the brains of our dashboard; it processes all calls and displays them in the dashboard.

Finally, let’s add some CSS.

Create a file called “dashboard.css” and add the following:
body {
  font: 400 0.95em/1 "Proxima Nova", Helvetica,sans-serif;
  font-size: .875em;
  background-color: #f0f0f0;
  padding-top: 90px;
}
.widget {
  -webkit-box-shadow: #f0f0f0 0 0 8px;
  -moz-box-shadow: #f0f0f0 0 0 8px;
  box-shadow: #f0f0f0 0 0 8px;
  background-color: #f0f0f0;
  margin-bottom: 30px;
}
.widget h1 {
  font-size: 1.0em;
  margin: 0 0 .4em;
  font-weight: bold;
}
.widget .widget-inner>header, .widget .widget-inner>footer {
  font-size: 12px;
  text-shadow: 1px 1px #0e0e0e;
}
.widget .widget-inner>header {
  background-color: #272727;
  text-transform: uppercase;
  padding: 16px 12px 16px 26px;
  font-weight: 700;
}
.widget .widget-inner {
  border: solid 1px #e5e5e5;
  background-color: #fff;
}
.widget .widget-inner>header {
  background-color: #f5f5f5;
}
.widget .widget-inner>header h1 {
  color: #8b8b8b;
  text-shadow: 1px 1px #fff;
  margin-bottom: 0;
}
.widget .widget-body {
  color: #666;
  height: 225px
}
.widget .widget-body {
  padding: 16px;
  color: #d3d4d4;
  font-family: Helvetica, Arial, sans-serif;
  z-index: 1;
}
.widget .widget-inner>footer {
  color: #8b8b8b;
  background-color: #f5f5f5;
  text-shadow: 1px 1px #fff;
}
.dash-unit {
  margin-bottom: 30px;
  padding-bottom: 10px;
  border: 1px solid #e5e5e5;
  /*background-image: url('../img/sep-half.png');*/
  background-color: #f5f5f5;
  color: #8b8b8b;
  height: 290px;
  text-align: center;
}
.dash-unit dtitle {
  font-size: 11px;
  text-transform: uppercase;
  margin: 8px;
  padding: 0px;
  height: inherit;
}
.dash-unit hr {
  border: 0;
  border-top: 1px solid #151515;
  border-top-style: dashed;
  margin-top: 3px;
}

Summary

You can run this anywhere you want. You just have to point your Twilio phone number(s) you want to track to the URL you add to this site with /call as the endpoint. You can see the full codebase at GitHub: https://github.com/flybaseio/call-tracking.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset