Colored status in list and member additional infos

This commit is contained in:
Dominique Da Silva 2019-11-09 00:52:54 +00:00
parent 4f235b9ac3
commit 456de3414a
9 changed files with 180 additions and 12 deletions

View file

@ -186,6 +186,23 @@ templates=[
["aves", "MJML Template"]
]
[grapejs.mjml]
# Editor main background color
editorBackgroundColor = "#202835"
# Editor canvas background (light, dark, bluish, custom css)
canvasBackgroundStyle = "bluish"
# Color for the head and attributes labels
canvasLabelsColor = "#4b5666"
[views.template]
showeditor = false
[views.lists]
statuscolored = false
[reports]
# The whole reporting functionality can be disabled below if the they are not needed and the DB cannot be
# properly protected.

File diff suppressed because one or more lines are too long

BIN
public/css/flags/flags.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View file

@ -8,7 +8,7 @@ html {
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
margin-bottom: 70px;
}
.footer {

View file

@ -1,16 +1,28 @@
@import "flags/flags.css";
.glyphicon.spinning {
animation: spin 1s infinite linear;
-webkit-animation: spin2 1s infinite linear;
}
@keyframes spin {
from { transform: scale(1) rotate(0deg); }
to { transform: scale(1) rotate(360deg); }
from {
transform: scale(1) rotate(0deg);
}
to {
transform: scale(1) rotate(360deg);
}
}
@-webkit-keyframes spin2 {
from { -webkit-transform: rotate(0deg); }
to { -webkit-transform: rotate(360deg); }
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
/* Supporting wider description lists */
@ -23,11 +35,25 @@
.dl-horizontal dd {
margin-left: 220px;
}
}
@media screen and (max-width: 767px) {
.text-xs-center {
text-align: center;
}
.form-group .col-xs-12 button {
margin-bottom: 20px;
}
}
h2 .glyphicon {
font-size: .75em;
}
h3 .glyphicon {
font-size: .8em;
}
@ -46,4 +72,78 @@ tbody>tr.selected {
.row-actions .row-action:last-child {
padding-right: 0px;
}
span.subscriber-status-1 {
/* subscribed */
color: #2b5718;
}
span.subscriber-status-0,
span.subscriber-status-2 {
/* unknow / unsubscribed */
color: #b3aba0;
}
span.subscriber-status-3 {
/* bounced */
color: #aa3203;
}
span.subscriber-status-4 {
/* complained */
color: #7b0833;
}
/* subscriber line status */
tr.subscriber-status-1 td:first-child {
border-right: solid 3px #87ad77;
text-align:center;
padding-right: 10px;
}
tr.subscriber-status-0 td:first-child,
tr.subscriber-status-2 td:first-child {
border-right: solid 3px #c7bfb4;
text-align:center;
padding-right: 10px;
}
tr.subscriber-status-3 td:first-child {
border-right: solid 3px #df6b3d;
text-align:center;
padding-right: 10px;
}
tr.subscriber-status-4 td:first-child {
border-right: solid 3px #c94475;
text-align:center;
padding-right: 10px;
}
/* subscribers status icon */
.status-icon {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 4px;
vertical-align: middle;
}
.status-icon.subscriber-status-1 {
background-color: #2b5718;
}
.status-icon.subscriber-status-0,
.status-icon.subscriber-status-2 {
background-color: #b3aba0;
}
.status-icon.subscriber-status-3 {
background-color: #aa3203;
}
.status-icon.subscriber-status-4 {
background-color: #7b0833;
}

View file

@ -12,6 +12,7 @@ let forms = require('../lib/models/forms');
let tools = require('../lib/tools');
let striptags = require('striptags');
let htmlescape = require('escape-html');
let getName = require('country-list').getName;
let multer = require('multer');
let os = require('os');
let humanize = require('humanize');
@ -167,7 +168,7 @@ router.post('/ajax', (req, res) => {
'<code>' + row.cid + '</code>',
row.subscribers,
htmlescape(striptags(row.description) || ''),
'<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span><a href="/lists/edit/' + row.id + '">' + _('Edit') + '</a>' ]
'<span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> <a href="/lists/edit/' + row.id + '">' + _('Edit') + '</a>' ]
)
});
});
@ -254,7 +255,7 @@ router.post('/ajax/:id', (req, res) => {
} else {
return htmlescape(cRow.value || '');
}
})).concat(statuses[row.status]).concat(row.created && row.created.toISOString ? '<span class="datestring" data-date="' + row.created.toISOString() + '" title="' + row.created.toISOString() + '">' + row.created.toISOString() + '</span>' : 'N/A').concat('<a href="/lists/subscription/' + list.id + '/edit/' + row.cid + '">' + _('Edit') + '</a>'))
})).concat(config.views.lists.statuscolored ? '<span class="subscriber-status-' + row.status + '">' + statuses[row.status] + '</span>' : statuses[row.status]).concat(row.created && row.created.toISOString ? '<span class="datestring" data-date="' + row.created.toISOString() + '" title="' + row.created.toISOString() + '">' + row.created.toISOString() + '</span>' : 'N/A').concat('<a href="/lists/subscription/' + list.id + '/edit/' + row.cid + '">' + _('Edit') + '</a>'))
});
});
});
@ -312,6 +313,7 @@ router.get('/view/:id', passport.csrfProtection, (req, res) => {
list.csrfToken = req.csrfToken();
list.customFields = fieldList.filter(field => field.visible);
list.customSort = list.customFields.length ? ',' + list.customFields.map(() => '0').join(',') : '';
list.statusColored = config.views.lists.statuscolored;
list.showSubscriptions = req.query.tab === 'subscriptions' || !req.query.tab;
list.showImports = req.query.tab === 'imports';
@ -387,14 +389,27 @@ router.get('/subscription/:id/edit/:cid', passport.csrfProtection, (req, res) =>
fieldList = [];
}
let statuses = [_('Unknown'), _('Subscribed'), _('Unsubscribed'), _('Bounced'), _('Complained')];
subscription.list = list;
subscription.csrfToken = req.csrfToken();
subscription.customFields = fields.getRow(fieldList, subscription, false, true);
subscription.useEditor = true;
subscription.createdDate = moment(subscription.created).format('lll');
subscription.modifiedDate = moment(subscription.statusChange).format('lll');
subscription.statusTitle = statuses[subscription.status];
subscription.isSubscribed = subscription.status === 1;
subscription.isBounced = subscription.status === 3;
let country = {};
if (subscription.optInCountry) {
country.name = getName(subscription.optInCountry);
country.code = subscription.optInCountry.toLowerCase();
}
subscription.country = country;
let tzfound = false;
subscription.timezones = moment.tz.names().map(tz => {
let selected = false;

View file

@ -147,7 +147,7 @@
<footer class="footer">
<div class="container">
<p class="text-muted">&copy; 2016 Kreata OÜ <a href="https://mailtrain.org">Mailtrain.org</a>, <a href="mailto:info@mailtrain.org">info@mailtrain.org</a>. <a href="https://github.com/Mailtrain-org/mailtrain">{{#translate}}Source on GitHub{{/translate}}</a></p>
<p class="text-muted">&copy; 2016 Kreata OÜ <a href="https://mailtrain.org">Mailtrain.org</a><span class="hidden-xs">, <a href="mailto:info@mailtrain.org">info@mailtrain.org</a>. <a href="https://github.com/Mailtrain-org/mailtrain">{{#translate}}Source on GitHub{{/translate}}</a></span></p>
</div>
</footer>

View file

@ -41,12 +41,28 @@
<input type="hidden" name="cid" value="{{cid}}">
<div class="form-group">
<label for="email" class="col-sm-2 control-label">{{#translate}}Email address{{/translate}}</label>
<label for="email" class="col-sm-2 control-label" style="padding-top: 12px;">{{#translate}}Email address{{/translate}}</label>
<div class="col-sm-10">
<input type="email" class="form-control input-lg" name="email" id="email" placeholder="" value="{{email}}" required>
</div>
</div>
<div class="form-group text-xs-center">
<div class="col-sm-offset-2 col-sm-10">
<span>
<b>{{#translate}}Status{{/translate}}</b> <i class="status-icon subscriber-status-{{status}}"></i> <span class="subscriber-status-{{status}}">{{statusTitle}}</span>
{{#if country.code }}
<span class="hidden-xs">  |  </span><br class="visible-xs" />
<i class="flag flag-{{country.code}}" title="{{country.name}}"></i> {{country.name}}
{{/if}}
<span class="hidden-xs">  |  </span><br class="visible-xs" />
<b>{{#translate}}Created{{/translate}}</b> {{createdDate}}
<span class="hidden-xs">  |  </span><br class="visible-xs" />
<b>{{#translate}}Modified{{/translate}}</b> {{modifiedDate}}
</span>
</div>
</div>
<div class="form-group">
<label for="first-name" class="col-sm-2 control-label">{{#translate}}First Name{{/translate}}</label>
<div class="col-sm-10">
@ -163,6 +179,7 @@
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
@ -177,7 +194,10 @@
<hr />
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="col-xs-12 col-sm-push-2 col-sm-4">
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-ok"></i> {{#translate}}Update{{/translate}}</button>
</div>
<div class="col-xs-12 col-sm-8">
<div class="pull-right">
<button type="submit" form="subscriber-blacklist" class="btn btn-danger"><span class="glyphicon glyphicon-ban-circle"></span> {{#translate}}Blacklist{{/translate}}</button>
{{#if isSubscribed}}
@ -188,8 +208,7 @@
{{/if}}
<button type="submit" form="subscriber-delete" class="btn btn-danger"><i class="glyphicon glyphicon-remove"></i> {{#translate}}Delete Subscription{{/translate}}</button>
</div>
<button type="submit" class="btn btn-primary"><i class="glyphicon glyphicon-ok"></i> {{#translate}}Update{{/translate}}</button>
</div>
</div>
</form>

View file

@ -205,3 +205,16 @@
{{/if}}
</div>
</div>
{{#if statusColored }}
<script>
function updateSubscribersRows () {
for (i = 0; i < 5; i++) {
$('.dataTable tr:has(span.subscriber-status-' + i + ')').addClass('subscriber-status-' + i);
}
}
document.addEventListener("DOMContentLoaded", function (event) {
updateSubscribersRows();
$('body').on('DOMSubtreeModified', '.dataTables_info', updateSubscribersRows);
});
</script>
{{/if}}