2015-08-12 02:12:09 +00:00
|
|
|
var map = null
|
2015-07-29 00:31:12 +00:00
|
|
|
|
2015-08-12 02:12:09 +00:00
|
|
|
// statuses is a helper map to point result statuses to ui classes
|
|
|
|
var statuses = {
|
2016-01-17 04:59:40 +00:00
|
|
|
"Email Sent": {
|
2015-08-05 02:27:04 +00:00
|
|
|
slice: "ct-slice-donut-sent",
|
2015-08-12 02:12:09 +00:00
|
|
|
legend: "ct-legend-sent",
|
2016-01-29 15:55:49 +00:00
|
|
|
label: "label-success",
|
|
|
|
icon: "fa-envelope"
|
2015-08-05 02:27:04 +00:00
|
|
|
},
|
2016-01-17 04:59:40 +00:00
|
|
|
"Email Opened": {
|
2015-08-05 02:27:04 +00:00
|
|
|
slice: "ct-slice-donut-opened",
|
2015-08-12 02:12:09 +00:00
|
|
|
legend: "ct-legend-opened",
|
2016-01-29 15:55:49 +00:00
|
|
|
label: "label-warning",
|
|
|
|
icon: "fa-envelope"
|
2015-08-05 02:27:04 +00:00
|
|
|
},
|
2016-01-17 04:59:40 +00:00
|
|
|
"Clicked Link": {
|
2015-08-05 02:27:04 +00:00
|
|
|
slice: "ct-slice-donut-clicked",
|
2015-08-12 02:12:09 +00:00
|
|
|
legend: "ct-legend-clicked",
|
2016-01-29 15:55:49 +00:00
|
|
|
label: "label-danger",
|
|
|
|
icon: "fa-mouse-pointer"
|
2015-08-12 02:12:09 +00:00
|
|
|
},
|
2016-01-17 04:59:40 +00:00
|
|
|
"Success": {
|
2015-08-12 02:12:09 +00:00
|
|
|
slice: "ct-slice-donut-clicked",
|
|
|
|
legend: "ct-legend-clicked",
|
2016-01-29 15:55:49 +00:00
|
|
|
label: "label-danger",
|
|
|
|
icon: "fa-exclamation"
|
2015-08-05 02:27:04 +00:00
|
|
|
},
|
2016-01-17 04:59:40 +00:00
|
|
|
"Error": {
|
2015-08-05 02:27:04 +00:00
|
|
|
slice: "ct-slice-donut-error",
|
2015-08-12 02:12:09 +00:00
|
|
|
legend: "ct-legend-error",
|
2016-01-29 15:55:49 +00:00
|
|
|
label: "label-default",
|
|
|
|
icon: "fa-times"
|
2015-09-28 03:25:38 +00:00
|
|
|
},
|
2016-01-29 18:34:29 +00:00
|
|
|
"Error Sending Email": {
|
|
|
|
slice: "ct-slice-donut-error",
|
|
|
|
legend: "ct-legend-error",
|
|
|
|
label: "label-default",
|
|
|
|
icon: "fa-times"
|
|
|
|
},
|
2016-02-01 01:50:41 +00:00
|
|
|
"Submitted Data":{
|
|
|
|
slice: "ct-slice-donut-clicked",
|
|
|
|
legend: "ct-legend-clicked",
|
|
|
|
label: "label-danger",
|
|
|
|
icon: "fa-exclamation"
|
|
|
|
},
|
2016-01-17 04:59:40 +00:00
|
|
|
"Unknown": {
|
|
|
|
slice: "ct-slice-donut-error",
|
|
|
|
legend: "ct-legend-error",
|
2016-01-29 15:55:49 +00:00
|
|
|
label: "label-default",
|
|
|
|
icon: "fa-question"
|
|
|
|
},
|
|
|
|
"Campaign Created": {
|
|
|
|
label: "label-success",
|
|
|
|
icon: "fa-rocket"
|
2015-08-05 02:27:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-29 00:31:12 +00:00
|
|
|
var campaign = {}
|
|
|
|
|
2016-01-17 04:59:40 +00:00
|
|
|
function dismiss() {
|
2015-07-29 00:31:12 +00:00
|
|
|
$("#modal\\.flashes").empty()
|
|
|
|
$("#modal").modal('hide')
|
2015-07-30 03:31:39 +00:00
|
|
|
$("#resultsTable").dataTable().DataTable().clear().draw()
|
2015-07-29 00:31:12 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 03:31:39 +00:00
|
|
|
// Deletes a campaign after prompting the user
|
2016-01-17 04:59:40 +00:00
|
|
|
function deleteCampaign() {
|
|
|
|
if (confirm("Are you sure you want to delete: " + campaign.name + "?")) {
|
2015-07-30 03:31:39 +00:00
|
|
|
api.campaignId.delete(campaign.id)
|
2016-01-17 04:59:40 +00:00
|
|
|
.success(function(msg) {
|
2016-01-17 19:25:13 +00:00
|
|
|
location.href = '/campaigns'
|
2016-01-17 04:59:40 +00:00
|
|
|
})
|
|
|
|
.error(function(e) {
|
|
|
|
$("#modal\\.flashes").empty().append("<div style=\"text-align:center\" class=\"alert alert-danger\">\
|
2015-07-30 03:31:39 +00:00
|
|
|
<i class=\"fa fa-exclamation-circle\"></i> " + data.responseJSON.message + "</div>")
|
2016-01-17 04:59:40 +00:00
|
|
|
})
|
2015-07-29 00:31:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-21 00:45:53 +00:00
|
|
|
// Exports campaign results as a CSV file
|
2016-01-29 19:18:06 +00:00
|
|
|
function exportAsCSV(scope) {
|
2016-01-21 00:45:53 +00:00
|
|
|
exportHTML = $("#exportButton").html()
|
2016-01-29 19:18:06 +00:00
|
|
|
var csvScope = null
|
|
|
|
switch (scope) {
|
|
|
|
case "results":
|
|
|
|
csvScope = campaign.results
|
|
|
|
break;
|
|
|
|
case "events":
|
|
|
|
csvScope = campaign.timeline
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!csvScope){return}
|
2016-01-21 00:45:53 +00:00
|
|
|
$("#exportButton").html('<i class="fa fa-spinner fa-spin"></i>')
|
2016-01-29 19:18:06 +00:00
|
|
|
var csvString = Papa.unparse(csvScope, {})
|
2016-01-21 00:45:53 +00:00
|
|
|
var csvData = new Blob([csvString], {
|
|
|
|
type: 'text/csv;charset=utf-8;'
|
|
|
|
});
|
|
|
|
if (navigator.msSaveBlob) {
|
2016-01-29 19:18:06 +00:00
|
|
|
navigator.msSaveBlob(csvData, scope + '.csv');
|
2016-01-21 00:45:53 +00:00
|
|
|
} else {
|
|
|
|
var csvURL = window.URL.createObjectURL(csvData);
|
2016-01-29 14:31:58 +00:00
|
|
|
var dlLink = document.createElement('a');
|
|
|
|
dlLink.href = csvURL;
|
2016-01-29 19:18:06 +00:00
|
|
|
dlLink.setAttribute('download', scope + '.csv');
|
2016-01-29 14:31:58 +00:00
|
|
|
dlLink.click();
|
2016-01-21 00:45:53 +00:00
|
|
|
}
|
|
|
|
$("#exportButton").html(exportHTML)
|
|
|
|
}
|
|
|
|
|
2016-01-29 14:31:58 +00:00
|
|
|
function renderTimeline(data) {
|
|
|
|
record = {
|
2016-01-29 15:55:49 +00:00
|
|
|
"first_name": data[1],
|
|
|
|
"last_name": data[2],
|
|
|
|
"email": data[3],
|
|
|
|
"position": data[4]
|
|
|
|
}
|
|
|
|
results = '<div class="timeline col-sm-12 well well-lg">' +
|
2016-01-29 14:31:58 +00:00
|
|
|
'<h6>Timeline for ' + record.first_name + ' ' + record.last_name +
|
|
|
|
'</h6><span class="subtitle">Email: ' + record.email + '</span>' +
|
2016-01-29 15:55:49 +00:00
|
|
|
'<div class="timeline-graph col-sm-6">'
|
2016-01-29 14:31:58 +00:00
|
|
|
$.each(campaign.timeline, function(i, event) {
|
|
|
|
if (!event.email || event.email == record.email) {
|
2016-01-29 15:55:49 +00:00
|
|
|
// Add the event
|
2016-01-29 14:31:58 +00:00
|
|
|
results += '<div class="timeline-entry">' +
|
2016-01-29 15:55:49 +00:00
|
|
|
' <div class="timeline-bar"></div>'
|
|
|
|
results +=
|
|
|
|
' <div class="timeline-icon ' + statuses[event.message].label + '">' +
|
|
|
|
' <i class="fa ' + statuses[event.message].icon + '"></i></div>' +
|
|
|
|
' <div class="timeline-message">' + event.message +
|
2016-02-01 01:50:41 +00:00
|
|
|
' <span class="timeline-date">' + moment(event.time).format('MMMM Do YYYY h:mm') + '</span>'
|
|
|
|
if (event.details) {
|
|
|
|
results += '<div class="timeline-event-details"><i class="fa fa-caret-right"></i> View Details</div>'
|
|
|
|
}
|
|
|
|
results += '</div></div>'
|
2016-01-29 14:31:58 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
results += '</div></div>'
|
|
|
|
return results
|
|
|
|
}
|
2016-01-17 04:59:40 +00:00
|
|
|
$(document).ready(function() {
|
2015-07-30 03:31:39 +00:00
|
|
|
campaign.id = window.location.pathname.split('/').slice(-1)[0]
|
|
|
|
api.campaignId.get(campaign.id)
|
2016-01-17 04:59:40 +00:00
|
|
|
.success(function(c) {
|
|
|
|
campaign = c
|
|
|
|
if (campaign) {
|
|
|
|
// Set the title
|
|
|
|
$("#page-title").text("Results for " + c.name)
|
|
|
|
// Setup tooltips
|
|
|
|
$('[data-toggle="tooltip"]').tooltip()
|
|
|
|
// Setup our graphs
|
|
|
|
var timeline_data = {
|
|
|
|
series: [{
|
|
|
|
name: "Events",
|
|
|
|
data: []
|
|
|
|
}]
|
2015-08-01 20:35:32 +00:00
|
|
|
}
|
2016-01-17 04:59:40 +00:00
|
|
|
var email_data = {
|
|
|
|
series: []
|
2015-07-31 04:07:54 +00:00
|
|
|
}
|
2016-01-17 04:59:40 +00:00
|
|
|
var email_legend = {}
|
|
|
|
var email_series_data = {}
|
|
|
|
var timeline_opts = {
|
|
|
|
axisX: {
|
|
|
|
showGrid: false,
|
|
|
|
type: Chartist.FixedScaleAxis,
|
|
|
|
divisor: 5,
|
|
|
|
labelInterpolationFnc: function(value) {
|
|
|
|
return moment(value).format('MMMM Do YYYY h:mm')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
axisY: {
|
|
|
|
type: Chartist.FixedScaleAxis,
|
|
|
|
ticks: [0, 1, 2],
|
|
|
|
low: 0,
|
|
|
|
showLabel: false
|
|
|
|
},
|
|
|
|
showArea: false,
|
|
|
|
plugins: []
|
2015-08-05 02:27:04 +00:00
|
|
|
}
|
2016-01-17 04:59:40 +00:00
|
|
|
var email_opts = {
|
|
|
|
donut: true,
|
|
|
|
donutWidth: 40,
|
|
|
|
chartPadding: 0,
|
|
|
|
showLabel: false
|
|
|
|
}
|
|
|
|
// Setup the results table
|
2016-01-29 14:31:58 +00:00
|
|
|
resultsTable = $("#resultsTable").DataTable({
|
|
|
|
destroy: true,
|
|
|
|
destroy: true,
|
|
|
|
"order": [
|
|
|
|
[1, "asc"]
|
|
|
|
],
|
|
|
|
columnDefs: [{
|
|
|
|
orderable: false,
|
|
|
|
targets: "no-sort"
|
|
|
|
}, {
|
|
|
|
className: "details-control",
|
|
|
|
"targets": [0]
|
|
|
|
}]
|
|
|
|
});
|
2016-01-17 04:59:40 +00:00
|
|
|
$.each(campaign.results, function(i, result) {
|
|
|
|
label = statuses[result.status].label || "label-default";
|
|
|
|
resultsTable.row.add([
|
2016-01-29 14:31:58 +00:00
|
|
|
"<i class=\"fa fa-caret-right\"></i>",
|
2016-01-17 04:59:40 +00:00
|
|
|
result.first_name || "",
|
|
|
|
result.last_name || "",
|
|
|
|
result.email || "",
|
|
|
|
result.position || "",
|
|
|
|
"<span class=\"label " + label + "\">" + result.status + "</span>"
|
|
|
|
]).draw()
|
|
|
|
if (!email_series_data[result.status]) {
|
|
|
|
email_series_data[result.status] = 1
|
|
|
|
} else {
|
|
|
|
email_series_data[result.status]++;
|
|
|
|
}
|
|
|
|
})
|
2016-01-29 14:31:58 +00:00
|
|
|
// Setup the individual timelines
|
|
|
|
$('#resultsTable tbody').on('click', 'td.details-control', function() {
|
|
|
|
var tr = $(this).closest('tr');
|
|
|
|
var row = resultsTable.row(tr);
|
|
|
|
|
|
|
|
if (row.child.isShown()) {
|
|
|
|
// This row is already open - close it
|
|
|
|
row.child.hide();
|
|
|
|
tr.removeClass('shown');
|
2016-01-29 15:55:49 +00:00
|
|
|
$(this).find("i").removeClass("fa-caret-down")
|
|
|
|
$(this).find("i").addClass("fa-caret-right")
|
2016-01-29 14:31:58 +00:00
|
|
|
} else {
|
|
|
|
// Open this row
|
2016-01-29 15:55:49 +00:00
|
|
|
$(this).find("i").removeClass("fa-caret-right")
|
|
|
|
$(this).find("i").addClass("fa-caret-down")
|
2016-01-29 14:31:58 +00:00
|
|
|
row.child(renderTimeline(row.data())).show();
|
|
|
|
tr.addClass('shown');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// Setup the graphs
|
2016-01-17 04:59:40 +00:00
|
|
|
$.each(campaign.timeline, function(i, event) {
|
|
|
|
timeline_data.series[0].data.push({
|
|
|
|
meta: i,
|
|
|
|
x: new Date(event.time),
|
|
|
|
y: 1
|
|
|
|
})
|
|
|
|
})
|
|
|
|
$.each(email_series_data, function(status, count) {
|
|
|
|
email_data.series.push({
|
|
|
|
meta: status,
|
|
|
|
value: count
|
|
|
|
})
|
|
|
|
})
|
|
|
|
var timeline_chart = new Chartist.Line('#timeline_chart', timeline_data, timeline_opts)
|
|
|
|
// Setup the overview chart listeners
|
|
|
|
$chart = $("#timeline_chart")
|
|
|
|
var $toolTip = $chart
|
|
|
|
.append('<div class="chartist-tooltip"></div>')
|
|
|
|
.find('.chartist-tooltip')
|
|
|
|
.hide();
|
|
|
|
$chart.on('mouseenter', '.ct-point', function() {
|
|
|
|
var $point = $(this)
|
|
|
|
value = $point.attr('ct:value')
|
|
|
|
cidx = $point.attr('ct:meta')
|
|
|
|
html = "Event: " + campaign.timeline[cidx].message
|
|
|
|
if (campaign.timeline[cidx].email) {
|
|
|
|
html += '<br>' + "Email: " + campaign.timeline[cidx].email
|
|
|
|
}
|
|
|
|
$toolTip.html(html).show()
|
|
|
|
});
|
|
|
|
$chart.on('mouseleave', '.ct-point', function() {
|
|
|
|
$toolTip.hide();
|
|
|
|
});
|
|
|
|
$chart.on('mousemove', function(event) {
|
|
|
|
$toolTip.css({
|
|
|
|
left: (event.offsetX || event.originalEvent.layerX) - $toolTip.width() / 2 - 10,
|
|
|
|
top: (event.offsetY + 70 || event.originalEvent.layerY) - $toolTip.height() - 40
|
|
|
|
});
|
|
|
|
});
|
|
|
|
var email_chart = new Chartist.Pie("#email_chart", email_data, email_opts)
|
|
|
|
email_chart.on('draw', function(data) {
|
|
|
|
// We don't want to create the legend twice
|
|
|
|
if (!email_legend[data.meta]) {
|
|
|
|
console.log(data.meta)
|
|
|
|
$("#email_chart_legend").append('<li><span class="' + statuses[data.meta].legend + '"></span>' + data.meta + '</li>')
|
|
|
|
email_legend[data.meta] = true
|
|
|
|
}
|
|
|
|
data.element.addClass(statuses[data.meta].slice)
|
|
|
|
})
|
|
|
|
// Setup the average chart listeners
|
|
|
|
$piechart = $("#email_chart")
|
|
|
|
var $pietoolTip = $piechart
|
|
|
|
.append('<div class="chartist-tooltip"></div>')
|
|
|
|
.find('.chartist-tooltip')
|
|
|
|
.hide();
|
2015-08-01 20:35:32 +00:00
|
|
|
|
2016-01-17 04:59:40 +00:00
|
|
|
$piechart.on('mouseenter', '.ct-slice-donut', function() {
|
|
|
|
var $point = $(this)
|
|
|
|
value = $point.attr('ct:value')
|
|
|
|
label = $point.attr('ct:meta')
|
|
|
|
$pietoolTip.html(label + ': ' + value.toString()).show();
|
|
|
|
});
|
2015-08-01 20:35:32 +00:00
|
|
|
|
2016-01-17 04:59:40 +00:00
|
|
|
$piechart.on('mouseleave', '.ct-slice-donut', function() {
|
|
|
|
$pietoolTip.hide();
|
2015-08-01 20:35:32 +00:00
|
|
|
});
|
2016-01-17 04:59:40 +00:00
|
|
|
$piechart.on('mousemove', function(event) {
|
|
|
|
$pietoolTip.css({
|
|
|
|
left: (event.offsetX || event.originalEvent.layerX) - $pietoolTip.width() / 2 - 10,
|
|
|
|
top: (event.offsetY + 40 || event.originalEvent.layerY) - $pietoolTip.height() - 80
|
2016-01-04 06:04:10 +00:00
|
|
|
});
|
2016-01-17 04:59:40 +00:00
|
|
|
});
|
|
|
|
$("#loading").hide()
|
|
|
|
$("#campaignResults").show()
|
|
|
|
map = new Datamap({
|
|
|
|
element: document.getElementById("resultsMap"),
|
|
|
|
responsive: true,
|
|
|
|
fills: {
|
|
|
|
defaultFill: "#ffffff",
|
|
|
|
point: "#283F50"
|
|
|
|
},
|
|
|
|
geographyConfig: {
|
|
|
|
highlightFillColor: "#1abc9c",
|
|
|
|
borderColor: "#283F50"
|
|
|
|
},
|
|
|
|
bubblesConfig: {
|
|
|
|
borderColor: "#283F50"
|
|
|
|
}
|
|
|
|
});
|
|
|
|
bubbles = []
|
|
|
|
$.each(campaign.results, function(i, result) {
|
|
|
|
// Check that it wasn't an internal IP
|
|
|
|
if (result.latitude == 0 && result.longitude == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
newIP = true
|
|
|
|
$.each(bubbles, function(i, bubble) {
|
|
|
|
if (bubble.ip == result.ip) {
|
|
|
|
bubbles[i].radius += 1
|
|
|
|
newIP = false
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
if (newIP) {
|
|
|
|
console.log("Adding bubble at: ")
|
|
|
|
console.log({
|
|
|
|
latitude: result.latitude,
|
|
|
|
longitude: result.longitude,
|
|
|
|
name: result.ip,
|
|
|
|
fillKey: "point"
|
|
|
|
})
|
|
|
|
bubbles.push({
|
|
|
|
latitude: result.latitude,
|
|
|
|
longitude: result.longitude,
|
|
|
|
name: result.ip,
|
|
|
|
fillKey: "point",
|
|
|
|
radius: 2
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
map.bubbles(bubbles)
|
2016-01-04 06:04:10 +00:00
|
|
|
}
|
2016-01-17 04:59:40 +00:00
|
|
|
// Load up the map data (only once!)
|
|
|
|
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
|
|
|
|
if ($(e.target).attr('href') == "#overview") {
|
|
|
|
if (!map) {
|
|
|
|
map = new Datamap({
|
|
|
|
element: document.getElementById("resultsMap"),
|
|
|
|
responsive: true,
|
|
|
|
fills: {
|
|
|
|
defaultFill: "#ffffff"
|
|
|
|
},
|
|
|
|
geographyConfig: {
|
|
|
|
highlightFillColor: "#1abc9c",
|
|
|
|
borderColor: "#283F50"
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.error(function() {
|
|
|
|
$("#loading").hide()
|
|
|
|
errorFlash(" Campaign not found!")
|
2016-01-04 06:04:10 +00:00
|
|
|
})
|
2015-07-29 00:31:12 +00:00
|
|
|
})
|