Compare commits
1 commit
master
...
fixVisitor
Author | SHA1 | Date | |
---|---|---|---|
45d7c4b21d |
|
@ -202,29 +202,59 @@ FormSchema.virtual('analytics.views').get(function () {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
FormSchema.virtual('analytics.submissions').get(function () {
|
function getDeviceStatistics(visitors){
|
||||||
return this.submissions.length;
|
var newStatItem = function(){
|
||||||
});
|
return {
|
||||||
|
visits: 0,
|
||||||
|
responses: 0,
|
||||||
|
completion: 0,
|
||||||
|
average_time: 0,
|
||||||
|
total_time: 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
FormSchema.virtual('analytics.conversionRate').get(function () {
|
var stats = {
|
||||||
if(this.analytics && this.analytics.visitors && this.analytics.visitors.length > 0){
|
desktop: newStatItem(),
|
||||||
return this.submissions.length/this.analytics.visitors.length*100;
|
tablet: newStatItem(),
|
||||||
} else {
|
phone: newStatItem(),
|
||||||
return 0;
|
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 fieldDropoffs = [];
|
||||||
var visitors = this.analytics.visitors;
|
var visitors = form.analytics.visitors;
|
||||||
var that = this;
|
var that = form;
|
||||||
|
|
||||||
if(this.form_fields.length === 0) {
|
if(form.form_fields.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(var i=0; i<this.form_fields.length; i++){
|
for(var i=0; i<form.form_fields.length; i++){
|
||||||
var field = this.form_fields[i];
|
var field = form.form_fields[i];
|
||||||
|
|
||||||
if(field && !field.deletePreserved){
|
if(field && !field.deletePreserved){
|
||||||
|
|
||||||
|
@ -238,7 +268,7 @@ FormSchema.virtual('analytics.fields').get(function () {
|
||||||
|
|
||||||
var continueViews, nextIndex;
|
var continueViews, nextIndex;
|
||||||
|
|
||||||
if(i !== this.form_fields.length-1){
|
if(i !== form.form_fields.length-1){
|
||||||
continueViews = _.reduce(visitors, function(sum, visitorObj){
|
continueViews = _.reduce(visitors, function(sum, visitorObj){
|
||||||
nextIndex = that.form_fields.indexOf(_.find(that.form_fields, function(o) {
|
nextIndex = that.form_fields.indexOf(_.find(that.form_fields, function(o) {
|
||||||
return o._id+'' === visitorObj.lastActiveField+'';
|
return o._id+'' === visitorObj.lastActiveField+'';
|
||||||
|
@ -281,6 +311,36 @@ FormSchema.virtual('analytics.fields').get(function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
return fieldDropoffs;
|
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, {
|
FormSchema.plugin(timeStampPlugin, {
|
||||||
|
|
|
@ -62,49 +62,6 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
|
||||||
return (totalTime/numSubmissions).toFixed(0);
|
return (totalTime/numSubmissions).toFixed(0);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
$scope.DeviceStatistics = (function(){
|
|
||||||
var newStatItem = function(){
|
|
||||||
return {
|
|
||||||
visits: 0,
|
|
||||||
responses: 0,
|
|
||||||
completion: 0,
|
|
||||||
average_time: 0,
|
|
||||||
total_time: 0
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var stats = {
|
|
||||||
desktop: newStatItem(),
|
|
||||||
tablet: newStatItem(),
|
|
||||||
phone: newStatItem(),
|
|
||||||
other: newStatItem()
|
|
||||||
};
|
|
||||||
|
|
||||||
if($scope.myform.analytics && $scope.myform.analytics.visitors) {
|
|
||||||
var visitors = $scope.myform.analytics.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;
|
|
||||||
})();
|
|
||||||
|
|
||||||
var updateFields = $interval(initController, 1000000);
|
var updateFields = $interval(initController, 1000000);
|
||||||
|
|
||||||
$scope.$on('$destroy', function() {
|
$scope.$on('$destroy', function() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="submissions-table container">
|
<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-12 header-title">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{ 'TOTAL_VIEWS' | translate }}
|
{{ 'TOTAL_VIEWS' | translate }}
|
||||||
|
@ -19,15 +19,15 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 header-numbers">
|
<div class="col-xs-12 header-numbers">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{myform.analytics.visitors.length}}
|
{{myform.formAnalytics.visitors.length}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{myform.analytics.submissions}}
|
{{table.rows.length}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{myform.analytics.conversionRate | number:0}}%
|
{{myform.formAnalytics.conversionRate | number:0}}%
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
{{ 'UNIQUE_VISITS' | translate }}
|
{{ 'UNIQUE_VISITS' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.desktop.visits}}
|
{{myform.formformAnalytics.deviceStatistics.desktop.visits}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
{{ 'UNIQUE_VISITS' | translate }}
|
{{ 'UNIQUE_VISITS' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.tablet.visits}}
|
{{myform.formformAnalytics.deviceStatistics.tablet.visits}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
{{ 'UNIQUE_VISITS' | translate }}
|
{{ 'UNIQUE_VISITS' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.tablet.visits}}
|
{{myform.formformAnalytics.deviceStatistics.tablet.visits}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
{{ 'UNIQUE_VISITS' | translate }}
|
{{ 'UNIQUE_VISITS' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.other.visits}}
|
{{myform.formformAnalytics.deviceStatistics.other.visits}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
{{ 'RESPONSES' | translate }}
|
{{ 'RESPONSES' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.desktop.responses}}
|
{{myform.formformAnalytics.deviceStatistics.desktop.responses}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
{{ 'RESPONSES' | translate }}
|
{{ 'RESPONSES' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.tablet.responses}}
|
{{myform.formformAnalytics.deviceStatistics.tablet.responses}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
{{ 'RESPONSES' | translate }}
|
{{ 'RESPONSES' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.phone.responses}}
|
{{myform.formformAnalytics.deviceStatistics.phone.responses}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
{{ 'RESPONSES' | translate }}
|
{{ 'RESPONSES' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.other.responses}}
|
{{myform.formformAnalytics.deviceStatistics.other.responses}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -134,7 +134,7 @@
|
||||||
{{ 'COMPLETION_RATE' | translate }}
|
{{ 'COMPLETION_RATE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.desktop.completion}}%
|
{{myform.formformAnalytics.deviceStatistics.desktop.completion}}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@
|
||||||
{{ 'COMPLETION_RATE' | translate }}
|
{{ 'COMPLETION_RATE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.tablet.completion}}%
|
{{myform.formformAnalytics.deviceStatistics.tablet.completion}}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@
|
||||||
{{ 'COMPLETION_RATE' | translate }}
|
{{ 'COMPLETION_RATE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.phone.completion}}%
|
{{myform.formformAnalytics.deviceStatistics.phone.completion}}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@
|
||||||
{{ 'COMPLETION_RATE' | translate }}
|
{{ 'COMPLETION_RATE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.other.completion}}%
|
{{myform.formformAnalytics.deviceStatistics.other.completion}}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -172,7 +172,7 @@
|
||||||
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.desktop.average_time | secondsToDateTime | date:'mm:ss'}}
|
{{myform.formformAnalytics.deviceStatistics.desktop.average_time | secondsToDateTime | date:'mm:ss'}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@
|
||||||
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.tablet.average_time | secondsToDateTime | date:'mm:ss'}}
|
{{myform.formformAnalytics.deviceStatistics.tablet.average_time | secondsToDateTime | date:'mm:ss'}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@
|
||||||
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.phone.average_time | secondsToDateTime | date:'mm:ss'}}
|
{{myform.formformAnalytics.deviceStatistics.phone.average_time | secondsToDateTime | date:'mm:ss'}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@
|
||||||
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{DeviceStatistics.other.average_time | secondsToDateTime | date:'mm:ss'}}
|
{{myform.formformAnalytics.deviceStatistics.other.average_time | secondsToDateTime | date:'mm:ss'}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -221,7 +221,7 @@
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="col-xs-3">
|
||||||
{{fieldStats.field.title}}
|
{{fieldStats.field.title}}
|
||||||
|
|
Loading…
Reference in a new issue