added support for computing analytics on backend

This commit is contained in:
David Baldwynn 2017-10-28 11:35:34 +02:00 committed by wodka
parent b9428a5df5
commit 80fdcb5d4f
2 changed files with 100 additions and 40 deletions

View File

@ -201,29 +201,59 @@ FormSchema.virtual('analytics.views').get(function () {
}
});
FormSchema.virtual('analytics.submissions').get(function () {
return this.submissions.length;
});
function getDeviceStatistics(visitors){
var newStatItem = function(){
return {
visits: 0,
responses: 0,
completion: 0,
average_time: 0,
total_time: 0
};
};
FormSchema.virtual('analytics.conversionRate').get(function () {
if(this.analytics && this.analytics.visitors && this.analytics.visitors.length > 0){
return this.submissions.length/this.analytics.visitors.length*100;
} else {
return 0;
}
});
var stats = {
desktop: newStatItem(),
tablet: newStatItem(),
phone: newStatItem(),
other: newStatItem()
};
FormSchema.virtual('analytics.fields').get(function () {
if(visitors) {
for (var i = 0; i < visitors.length; i++) {
var visitor = visitors[i];
var deviceType = visitor.deviceType;
stats[deviceType].visits++;
if (visitor.isSubmitted) {
stats[deviceType].total_time = stats[deviceType].total_time + visitor.timeElapsed;
stats[deviceType].responses++;
}
if(stats[deviceType].visits) {
stats[deviceType].completion = 100*(stats[deviceType].responses / stats[deviceType].visits).toFixed(2);
}
if(stats[deviceType].responses){
stats[deviceType].average_time = (stats[deviceType].total_time / stats[deviceType].responses).toFixed(0);
}
}
}
return stats;
}
function getFieldAnalytics(form){
var fieldDropoffs = [];
var visitors = this.analytics.visitors;
var that = this;
var visitors = form.analytics.visitors;
var that = form;
if(!this.form_fields || this.form_fields.length === 0) {
if(!form.form_fields || form.form_fields.length === 0) {
return null;
}
for(var i=0; i<this.form_fields.length; i++){
var field = this.form_fields[i];
for(var i=0; i<form.form_fields.length; i++){
var field = form.form_fields[i];
if(field && !field.deletePreserved){
@ -237,7 +267,7 @@ FormSchema.virtual('analytics.fields').get(function () {
var continueViews, nextIndex;
if(i !== this.form_fields.length-1){
if(i !== form.form_fields.length-1){
continueViews = _.reduce(visitors, function(sum, visitorObj){
nextIndex = that.form_fields.indexOf(_.find(that.form_fields, function(o) {
return o._id+'' === visitorObj.lastActiveField+'';
@ -261,12 +291,12 @@ FormSchema.virtual('analytics.fields').get(function () {
var totalViews = dropoffViews+continueViews;
var continueRate = 0;
var dropoffRate = 0;
if(totalViews > 0){
continueRate = (continueViews/totalViews*100).toFixed(0);
dropoffRate = (dropoffViews/totalViews*100).toFixed(0);
}
fieldDropoffs[i] = {
dropoffViews: dropoffViews,
responses: continueViews,
@ -280,6 +310,36 @@ FormSchema.virtual('analytics.fields').get(function () {
}
return fieldDropoffs;
}
function getConversionRate(form, numSubmissions){
if(form.analytics && form.analytics.visitors && form.analytics.visitors.length > 0){
return numSubmissions.length/form.analytics.visitors.length*100;
} else {
return 0;
}
}
FormSchema.virtual('formAnalytics').get(function () {
var that = this;
mongoose.model('FormSubmission').find({ form: that._id })
.select("id")
.lean()
.exec(function(err, results){
if(err){
return null;
}
var submissionCount = results.count;
return {
fields: getFieldAnalytics(that),
submissions: submissionCount,
conversionRate: getConversionRate(that),
deviceStatistics: getDeviceStatistics(that.analytics.visitors)
}
});
});
FormSchema.plugin(timeStampPlugin, {

View File

@ -1,5 +1,5 @@
<div class="submissions-table container">
<div class="row text-center analytics">
<div class="row text-center formAnalytics">
<div class="col-xs-12 header-title">
<div class="col-xs-3">
{{ 'TOTAL_VIEWS' | translate }}
@ -19,15 +19,15 @@
</div>
<div class="col-xs-12 header-numbers">
<div class="col-xs-3">
{{myform.analytics.visitors.length}}
{{myform.formAnalytics.visitors.length}}
</div>
<div class="col-xs-3">
{{myform.analytics.submissions}}
{{table.rows.length}}
</div>
<div class="col-xs-3">
{{myform.analytics.conversionRate | number:0}}%
{{myform.formAnalytics.conversionRate | number:0}}%
</div>
<div class="col-xs-3">
@ -58,7 +58,7 @@
{{ 'UNIQUE_VISITS' | translate }}
</div>
<div class="row">
{{DeviceStatistics.desktop.visits}}
{{myform.formformAnalytics.deviceStatistics.desktop.visits}}
</div>
</div>
@ -67,7 +67,7 @@
{{ 'UNIQUE_VISITS' | translate }}
</div>
<div class="row">
{{DeviceStatistics.tablet.visits}}
{{myform.formformAnalytics.deviceStatistics.tablet.visits}}
</div>
</div>
@ -76,7 +76,7 @@
{{ 'UNIQUE_VISITS' | translate }}
</div>
<div class="row">
{{DeviceStatistics.tablet.visits}}
{{myform.formformAnalytics.deviceStatistics.tablet.visits}}
</div>
</div>
@ -85,7 +85,7 @@
{{ 'UNIQUE_VISITS' | translate }}
</div>
<div class="row">
{{DeviceStatistics.other.visits}}
{{myform.formformAnalytics.deviceStatistics.other.visits}}
</div>
</div>
</div>
@ -96,7 +96,7 @@
{{ 'RESPONSES' | translate }}
</div>
<div class="row">
{{DeviceStatistics.desktop.responses}}
{{myform.formformAnalytics.deviceStatistics.desktop.responses}}
</div>
</div>
@ -105,7 +105,7 @@
{{ 'RESPONSES' | translate }}
</div>
<div class="row">
{{DeviceStatistics.tablet.responses}}
{{myform.formformAnalytics.deviceStatistics.tablet.responses}}
</div>
</div>
@ -114,7 +114,7 @@
{{ 'RESPONSES' | translate }}
</div>
<div class="row">
{{DeviceStatistics.phone.responses}}
{{myform.formformAnalytics.deviceStatistics.phone.responses}}
</div>
</div>
@ -123,7 +123,7 @@
{{ 'RESPONSES' | translate }}
</div>
<div class="row">
{{DeviceStatistics.other.responses}}
{{myform.formformAnalytics.deviceStatistics.other.responses}}
</div>
</div>
</div>
@ -134,7 +134,7 @@
{{ 'COMPLETION_RATE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.desktop.completion}}%
{{myform.formformAnalytics.deviceStatistics.desktop.completion}}%
</div>
</div>
@ -143,7 +143,7 @@
{{ 'COMPLETION_RATE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.tablet.completion}}%
{{myform.formformAnalytics.deviceStatistics.tablet.completion}}%
</div>
</div>
@ -152,7 +152,7 @@
{{ 'COMPLETION_RATE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.phone.completion}}%
{{myform.formformAnalytics.deviceStatistics.phone.completion}}%
</div>
</div>
@ -161,7 +161,7 @@
{{ 'COMPLETION_RATE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.other.completion}}%
{{myform.formformAnalytics.deviceStatistics.other.completion}}%
</div>
</div>
</div>
@ -172,7 +172,7 @@
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.desktop.average_time | secondsToDateTime | date:'mm:ss'}}
{{myform.formformAnalytics.deviceStatistics.desktop.average_time | secondsToDateTime | date:'mm:ss'}}
</div>
</div>
@ -181,7 +181,7 @@
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.tablet.average_time | secondsToDateTime | date:'mm:ss'}}
{{myform.formformAnalytics.deviceStatistics.tablet.average_time | secondsToDateTime | date:'mm:ss'}}
</div>
</div>
@ -190,7 +190,7 @@
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.phone.average_time | secondsToDateTime | date:'mm:ss'}}
{{myform.formformAnalytics.deviceStatistics.phone.average_time | secondsToDateTime | date:'mm:ss'}}
</div>
</div>
@ -199,7 +199,7 @@
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
</div>
<div class="row">
{{DeviceStatistics.other.average_time | secondsToDateTime | date:'mm:ss'}}
{{myform.formformAnalytics.deviceStatistics.other.average_time | secondsToDateTime | date:'mm:ss'}}
</div>
</div>
</div>
@ -221,7 +221,7 @@
</div>
</div>
<div class="col-xs-12 field-detailed-row" ng-repeat="fieldStats in myform.analytics.fields">
<div class="col-xs-12 field-detailed-row" ng-repeat="fieldStats in myform.formAnalytics.fields">
<div class="col-xs-3">
{{fieldStats.field.title}}