Added views for bounced/unsubscribed/complained etc.
This commit is contained in:
parent
97803b74ed
commit
408f021c36
9 changed files with 437 additions and 29 deletions
|
@ -194,6 +194,74 @@ module.exports.filterClickedSubscribers = (campaign, linkId, request, columns, c
|
|||
|
||||
};
|
||||
|
||||
module.exports.filterStatusSubscribers = (campaign, status, request, columns, callback) => {
|
||||
db.getConnection((err, connection) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
status = Number(status) || 0;
|
||||
let query = 'SELECT COUNT(`subscription__' + campaign.list + '`.`id`) AS total FROM `subscription__' + campaign.list + '` JOIN `campaign__' + campaign.id + '` ON `campaign__' + campaign.id + '`.`list`=? AND `campaign__' + campaign.id + '`.`segment`=? AND `campaign__' + campaign.id + '`.`subscription`=`subscription__' + campaign.list + '`.`id` WHERE `campaign__' + campaign.id + '`.`status`=?';
|
||||
let values = [campaign.list, campaign.segment, status];
|
||||
|
||||
connection.query(query, values, (err, total) => {
|
||||
if (err) {
|
||||
connection.release();
|
||||
return callback(err);
|
||||
}
|
||||
total = total && total[0] && total[0].total || 0;
|
||||
|
||||
let ordering = [];
|
||||
|
||||
if (request.order && request.order.length) {
|
||||
|
||||
request.order.forEach(order => {
|
||||
let orderField = columns[Number(order.column)];
|
||||
let orderDirection = (order.dir || '').toString().toLowerCase() === 'desc' ? 'DESC' : 'ASC';
|
||||
if (orderField) {
|
||||
ordering.push('`' + orderField + '` ' + orderDirection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!ordering.length) {
|
||||
ordering.push('`email` ASC');
|
||||
}
|
||||
|
||||
let args = [Number(request.length) || 50, Number(request.start) || 0];
|
||||
|
||||
if (request.search && request.search.value) {
|
||||
query = 'SELECT SQL_CALC_FOUND_ROWS * FROM `subscription__' + campaign.list + '` JOIN `campaign__' + campaign.id + '` ON `campaign__' + campaign.id + '`.`list`=? AND `campaign__' + campaign.id + '`.`segment`=? AND `campaign__' + campaign.id + '`.`subscription`=`subscription__' + campaign.list + '`.`id` WHERE `campaign__' + campaign.id + '`.`status`=? AND (email LIKE ? OR first_name LIKE ? OR last_name LIKE ?) ORDER BY ' + ordering.join(', ') + ' LIMIT ? OFFSET ?';
|
||||
|
||||
let searchVal = '%' + request.search.value.replace(/\\/g, '\\\\').replace(/([%_])/g, '\\$1') + '%';
|
||||
args = values.concat([searchVal, searchVal, searchVal]).concat(args);
|
||||
} else {
|
||||
query = 'SELECT SQL_CALC_FOUND_ROWS * FROM `subscription__' + campaign.list + '` JOIN `campaign__' + campaign.id + '` ON `campaign__' + campaign.id + '`.`list`=? AND `campaign__' + campaign.id + '`.`segment`=? AND `campaign__' + campaign.id + '`.`subscription`=`subscription__' + campaign.list + '`.`id` WHERE `campaign__' + campaign.id + '`.`status`=? ORDER BY ' + ordering.join(', ') + ' LIMIT ? OFFSET ?';
|
||||
args = values.concat(args);
|
||||
}
|
||||
|
||||
connection.query(query, args, (err, rows) => {
|
||||
if (err) {
|
||||
connection.release();
|
||||
return callback(err);
|
||||
}
|
||||
connection.query('SELECT FOUND_ROWS() AS total', (err, filteredTotal) => {
|
||||
connection.release();
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let subscriptions = rows.map(row => tools.convertKeys(row));
|
||||
|
||||
filteredTotal = filteredTotal && filteredTotal[0] && filteredTotal[0].total || 0;
|
||||
return callback(null, subscriptions, total, filteredTotal);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
module.exports.getByCid = (cid, callback) => {
|
||||
cid = (cid || '').toString().trim();
|
||||
if (!cid) {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"schemaVersion": 10
|
||||
"schemaVersion": 11
|
||||
}
|
||||
|
|
|
@ -321,8 +321,11 @@ router.get('/view/:id', passport.csrfProtection, (req, res) => {
|
|||
// show only messages that weren't bounced as delivered
|
||||
campaign.delivered = campaign.delivered - campaign.bounced;
|
||||
|
||||
campaign.openRate = campaign.delivered ? Math.round((campaign.opened / campaign.delivered) * 100) : 0;
|
||||
campaign.clicksRate = campaign.delivered ? Math.round((campaign.clicks / campaign.delivered) * 100) : 0;
|
||||
campaign.openRate = campaign.delivered ? Math.round((campaign.opened / campaign.delivered) * 10000)/100 : 0;
|
||||
campaign.clicksRate = campaign.delivered ? Math.round((campaign.clicks / campaign.delivered) * 10000)/100 : 0;
|
||||
campaign.bounceRate = campaign.delivered ? Math.round((campaign.bounced / campaign.delivered) * 10000)/100 : 0;
|
||||
campaign.complaintRate = campaign.delivered ? Math.round((campaign.complained / campaign.delivered) * 10000)/100 : 0;
|
||||
campaign.unsubscribeRate = campaign.delivered ? Math.round((campaign.unsubscribed / campaign.delivered) * 10000)/100 : 0;
|
||||
|
||||
campaigns.getLinks(campaign.id, (err, links) => {
|
||||
if (err) {
|
||||
|
@ -373,6 +376,52 @@ router.get('/opened/:id', passport.csrfProtection, (req, res) => {
|
|||
});
|
||||
});
|
||||
|
||||
router.get('/status/:id/:status', passport.csrfProtection, (req, res) => {
|
||||
let id = Number(req.params.id) || 0;
|
||||
let status;
|
||||
switch (req.params.status) {
|
||||
case 'delivered':
|
||||
status = 1;
|
||||
break;
|
||||
case 'unsubscribed':
|
||||
status = 2;
|
||||
break;
|
||||
case 'bounced':
|
||||
status = 3;
|
||||
break;
|
||||
case 'complained':
|
||||
status = 4;
|
||||
break;
|
||||
default:
|
||||
req.flash('danger', 'Unknown status selector');
|
||||
return res.redirect('/campaigns');
|
||||
}
|
||||
|
||||
campaigns.get(id, true, (err, campaign) => {
|
||||
if (err || !campaign) {
|
||||
req.flash('danger', err && err.message || err || 'Could not find campaign with specified ID');
|
||||
return res.redirect('/campaigns');
|
||||
}
|
||||
|
||||
lists.get(campaign.list, (err, list) => {
|
||||
if (err || !campaign) {
|
||||
req.flash('danger', err && err.message || err);
|
||||
return res.redirect('/campaigns');
|
||||
}
|
||||
|
||||
campaign.csrfToken = req.csrfToken();
|
||||
campaign.list = list;
|
||||
|
||||
// show only messages that weren't bounced as delivered
|
||||
campaign.delivered = campaign.delivered - campaign.bounced;
|
||||
campaign.clicksRate = campaign.delivered ? Math.round((campaign.clicks / campaign.delivered) * 100) : 0;
|
||||
campaign.status = status;
|
||||
|
||||
res.render('campaigns/' + req.params.status, campaign);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/clicked/:id/:linkId', passport.csrfProtection, (req, res) => {
|
||||
campaigns.get(req.params.id, true, (err, campaign) => {
|
||||
if (err || !campaign) {
|
||||
|
@ -460,6 +509,44 @@ router.post('/clicked/ajax/:id/:linkId', (req, res) => {
|
|||
});
|
||||
});
|
||||
|
||||
router.post('/status/ajax/:id/:status', (req, res) => {
|
||||
let status = Number(req.params.status) || 0;
|
||||
|
||||
campaigns.get(req.params.id, true, (err, campaign) => {
|
||||
if (err || !campaign) {
|
||||
return res.json({
|
||||
error: err && err.message || err || 'Campaign not found',
|
||||
data: []
|
||||
});
|
||||
}
|
||||
|
||||
let columns = ['#', 'email', 'first_name', 'last_name', 'campaign__' + campaign.id + '`.`updated'];
|
||||
campaigns.filterStatusSubscribers(campaign, status, req.body, columns, (err, data, total, filteredTotal) => {
|
||||
if (err) {
|
||||
return res.json({
|
||||
error: err.message || err,
|
||||
data: []
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
draw: req.body.draw,
|
||||
recordsTotal: total,
|
||||
recordsFiltered: filteredTotal,
|
||||
data: data.map((row, i) => [
|
||||
(Number(req.body.start) || 0) + 1 + i,
|
||||
htmlescape(row.email || ''),
|
||||
htmlescape(row.firstName || ''),
|
||||
htmlescape(row.lastName || ''),
|
||||
htmlescape(row.response || ''),
|
||||
row.updated && row.created.toISOString ? '<span class="datestring" data-date="' + row.updated.toISOString() + '" title="' + row.updated.toISOString() + '">' + row.updated.toISOString() + '</span>' : 'N/A',
|
||||
'<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span><a href="/lists/subscription/' + campaign.list + '/edit/' + row.cid + '">Edit</a>'
|
||||
])
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/delete', passport.parseForm, passport.csrfProtection, (req, res) => {
|
||||
campaigns.delete(req.body.id, (err, deleted) => {
|
||||
if (err) {
|
||||
|
|
15
setup/sql/upgrade-00011.sql
Normal file
15
setup/sql/upgrade-00011.sql
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Header section
|
||||
# Define incrementing schema version number
|
||||
SET @schema_version = '11';
|
||||
|
||||
-- {{#each tables.campaign}}
|
||||
|
||||
# Adds new index for 'status' on campaign messages table
|
||||
CREATE INDEX status_index ON `{{this}}` (`status`);
|
||||
|
||||
-- {{/each}}
|
||||
|
||||
# Footer section
|
||||
LOCK TABLES `settings` WRITE;
|
||||
INSERT INTO `settings` (`key`, `value`) VALUES('db_schema_version', @schema_version) ON DUPLICATE KEY UPDATE `value`=@schema_version;
|
||||
UNLOCK TABLES;
|
54
views/campaigns/bounced.hbs
Normal file
54
views/campaigns/bounced.hbs
Normal file
|
@ -0,0 +1,54 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/campaigns">Campaigns</a></li>
|
||||
{{#if parent}}
|
||||
<li><a href="/campaigns/view/{{parent.id}}">{{parent.name}}</a></li>
|
||||
{{/if}}
|
||||
<li><a href="/campaigns/view/{{id}}">{{name}}</a></li>
|
||||
<li class="active">Bounced info</li>
|
||||
</ol>
|
||||
|
||||
<h2><span class="glyphicon glyphicon-inbox" aria-hidden="true"></span> {{name}} <small>Bounced info</small> <a class="btn btn-default btn-xs" href="/campaigns/view/{{id}}?tab=overview" role="button"><span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span> View campaign</a></h2>
|
||||
|
||||
<hr>
|
||||
|
||||
{{#if description}}
|
||||
<div class="well well-sm">{{{description}}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<div class="panel panel-info">
|
||||
<!-- Default panel contents -->
|
||||
<div class="panel-heading">Subscribers who bounced and were unsubscribed:</div>
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table data-topic-url="/campaigns/status" data-topic-id="{{id}}/3" data-sort-column="1" data-sort-order="asc" class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,1,1,0,1,0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
</th>
|
||||
<th>
|
||||
Address
|
||||
</th>
|
||||
<th>
|
||||
First Name
|
||||
</th>
|
||||
<th>
|
||||
Last Name
|
||||
</th>
|
||||
<th>
|
||||
SMTP response
|
||||
</th>
|
||||
<th>
|
||||
Bounced
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
54
views/campaigns/complained.hbs
Normal file
54
views/campaigns/complained.hbs
Normal file
|
@ -0,0 +1,54 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/campaigns">Campaigns</a></li>
|
||||
{{#if parent}}
|
||||
<li><a href="/campaigns/view/{{parent.id}}">{{parent.name}}</a></li>
|
||||
{{/if}}
|
||||
<li><a href="/campaigns/view/{{id}}">{{name}}</a></li>
|
||||
<li class="active">Complained info</li>
|
||||
</ol>
|
||||
|
||||
<h2><span class="glyphicon glyphicon-inbox" aria-hidden="true"></span> {{name}} <small>Complained info</small> <a class="btn btn-default btn-xs" href="/campaigns/view/{{id}}?tab=overview" role="button"><span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span> View campaign</a></h2>
|
||||
|
||||
<hr>
|
||||
|
||||
{{#if description}}
|
||||
<div class="well well-sm">{{{description}}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<div class="panel panel-info">
|
||||
<!-- Default panel contents -->
|
||||
<div class="panel-heading">Subscribers who complained and were unsubscribed:</div>
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table data-topic-url="/campaigns/status" data-topic-id="{{id}}/4" data-sort-column="1" data-sort-order="asc" class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,1,1,0,1,0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
</th>
|
||||
<th>
|
||||
Address
|
||||
</th>
|
||||
<th>
|
||||
First Name
|
||||
</th>
|
||||
<th>
|
||||
Last Name
|
||||
</th>
|
||||
<th>
|
||||
SMTP response
|
||||
</th>
|
||||
<th>
|
||||
Complained
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
54
views/campaigns/delivered.hbs
Normal file
54
views/campaigns/delivered.hbs
Normal file
|
@ -0,0 +1,54 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/campaigns">Campaigns</a></li>
|
||||
{{#if parent}}
|
||||
<li><a href="/campaigns/view/{{parent.id}}">{{parent.name}}</a></li>
|
||||
{{/if}}
|
||||
<li><a href="/campaigns/view/{{id}}">{{name}}</a></li>
|
||||
<li class="active">Delivered info</li>
|
||||
</ol>
|
||||
|
||||
<h2><span class="glyphicon glyphicon-inbox" aria-hidden="true"></span> {{name}} <small>Delivered info</small> <a class="btn btn-default btn-xs" href="/campaigns/view/{{id}}?tab=overview" role="button"><span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span> View campaign</a></h2>
|
||||
|
||||
<hr>
|
||||
|
||||
{{#if description}}
|
||||
<div class="well well-sm">{{{description}}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<div class="panel panel-info">
|
||||
<!-- Default panel contents -->
|
||||
<div class="panel-heading">Subscribers who received the message:</div>
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table data-topic-url="/campaigns/status" data-topic-id="{{id}}/1" data-sort-column="1" data-sort-order="asc" class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,1,1,0,1,0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
</th>
|
||||
<th>
|
||||
Address
|
||||
</th>
|
||||
<th>
|
||||
First Name
|
||||
</th>
|
||||
<th>
|
||||
Last Name
|
||||
</th>
|
||||
<th>
|
||||
SMTP response
|
||||
</th>
|
||||
<th>
|
||||
Delivered
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
54
views/campaigns/unsubscribed.hbs
Normal file
54
views/campaigns/unsubscribed.hbs
Normal file
|
@ -0,0 +1,54 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/campaigns">Campaigns</a></li>
|
||||
{{#if parent}}
|
||||
<li><a href="/campaigns/view/{{parent.id}}">{{parent.name}}</a></li>
|
||||
{{/if}}
|
||||
<li><a href="/campaigns/view/{{id}}">{{name}}</a></li>
|
||||
<li class="active">Unsubscribed info</li>
|
||||
</ol>
|
||||
|
||||
<h2><span class="glyphicon glyphicon-inbox" aria-hidden="true"></span> {{name}} <small>Unsubscribed info</small> <a class="btn btn-default btn-xs" href="/campaigns/view/{{id}}?tab=overview" role="button"><span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span> View campaign</a></h2>
|
||||
|
||||
<hr>
|
||||
|
||||
{{#if description}}
|
||||
<div class="well well-sm">{{{description}}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="table-responsive">
|
||||
|
||||
<div class="panel panel-info">
|
||||
<!-- Default panel contents -->
|
||||
<div class="panel-heading">Subscribers who unsubscribed:</div>
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table data-topic-url="/campaigns/status" data-topic-id="{{id}}/2" data-sort-column="1" data-sort-order="asc" class="table table-bordered table-hover data-table-ajax display nowrap" width="100%" data-row-sort="0,1,1,1,0,1,0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1">
|
||||
#
|
||||
</th>
|
||||
<th>
|
||||
Address
|
||||
</th>
|
||||
<th>
|
||||
First Name
|
||||
</th>
|
||||
<th>
|
||||
Last Name
|
||||
</th>
|
||||
<th>
|
||||
SMTP response
|
||||
</th>
|
||||
<th>
|
||||
Unsubscribed
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -88,32 +88,54 @@
|
|||
{{#if isNormal}}
|
||||
|
||||
{{#unless isIdling}}
|
||||
<dt>Delivered</dt>
|
||||
<dt>Delivered <a href="/campaigns/status/{{id}}/delivered" title="List subscribers who received this message"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||
<dd>{{delivered}}</dd>
|
||||
|
||||
<dt>Bounced</dt>
|
||||
<dd>{{bounced}}</dd>
|
||||
</dl>
|
||||
<hr />
|
||||
<dl class="dl-horizontal">
|
||||
|
||||
<dt>Complaints</dt>
|
||||
<dd>{{complained}}</dd>
|
||||
|
||||
<dt>Unsubscribed</dt>
|
||||
<dd>{{unsubscribed}}</dd>
|
||||
|
||||
<dt><a href="/campaigns/opened/{{id}}" title="List subscribers who opened this message">Opened <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></a></dt>
|
||||
<dt>Bounced <a href="/campaigns/status/{{id}}/bounced" title="List subscribers who bounced"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||
<dd>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{openRate}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em; width: {{openRate}}%;">
|
||||
{{openRate}}%
|
||||
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{bounceRate}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 6em; width: {{bounceRate}}%;">
|
||||
{{bounced}} ({{bounceRate}}%)
|
||||
</div>
|
||||
</div>
|
||||
</dd>
|
||||
|
||||
<dt><a href="/campaigns/clicked/{{id}}/all" title="List subscribers who clicked on a link">Clicked <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></a></dt>
|
||||
<dt>Complaints <a href="/campaigns/status/{{id}}/complained" title="List subscribers who complained for this message"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||
<dd>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{clicksRate}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em; width: {{clicksRate}}%;">
|
||||
{{clicksRate}}%
|
||||
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="{{complaintRate}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 6em; width: {{complaintRate}}%;">
|
||||
{{complained}} ({{complaintRate}}%)
|
||||
</div>
|
||||
</div>
|
||||
</dd>
|
||||
|
||||
<dt>Unsubscribed <a href="/campaigns/status/{{id}}/unsubscribed" title="List subscribers who unsubscribed after this message"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||
<dd>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="{{unsubscribeRate}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 6em; width: {{unsubscribeRate}}%;">
|
||||
{{unsubscribed}} ({{unsubscribeRate}}%)
|
||||
</div>
|
||||
</div>
|
||||
</dd>
|
||||
|
||||
<dt>Opened <a href="/campaigns/opened/{{id}}" title="List subscribers who opened this message"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||
<dd>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{openRate}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 6em; width: {{openRate}}%;">
|
||||
{{opened}} ({{openRate}}%)
|
||||
</div>
|
||||
</div>
|
||||
</dd>
|
||||
|
||||
<dt>Clicked <a href="/campaigns/clicked/{{id}}/all" title="List subscribers who clicked on a link"> <span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a></dt>
|
||||
<dd>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{clicksRate}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 6em; width: {{clicksRate}}%;">
|
||||
{{clicks}} ({{clicksRate}}%)
|
||||
</div>
|
||||
</div>
|
||||
</dd>
|
||||
|
@ -295,7 +317,7 @@
|
|||
</td>
|
||||
<td>
|
||||
<div class="pull-right">
|
||||
<a href="/campaigns/clicked/{{../id}}/{{id}}" title="List subscribers who clicked this link"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></a>
|
||||
<a href="/campaigns/clicked/{{../id}}/{{id}}" title="List subscribers who clicked this link"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a>
|
||||
</div>
|
||||
{{clicks}}
|
||||
</td>
|
||||
|
@ -323,7 +345,7 @@
|
|||
</th>
|
||||
<th>
|
||||
<div class="pull-right">
|
||||
<a href="/campaigns/clicked/{{id}}/all" title="List subscribers who clicked on a link"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></a>
|
||||
<a href="/campaigns/clicked/{{id}}/all" title="List subscribers who clicked on a link"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></a>
|
||||
</div>
|
||||
{{clicks}}
|
||||
</th>
|
||||
|
|
Loading…
Reference in a new issue