diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js index 600ef7b0..7b35eaff 100644 --- a/app/controllers/forms.server.controller.js +++ b/app/controllers/forms.server.controller.js @@ -133,7 +133,7 @@ exports.listSubmissions = function(req, res) { FormSubmission.find({ form: _form._id }).sort('created').lean().exec(function(err, _submissions) { if (err) { console.error(err); - res.status(500).send({ + return res.status(500).send({ message: errorHandler.getErrorMessage(err) }); } @@ -141,6 +141,135 @@ exports.listSubmissions = function(req, res) { }); }; +/** + * Get Visitor Analytics Data for a given Form + */ +exports.getVisitorData = function(req, res) { + Form.aggregate([ + { + $match: { + _id: mongoose.Types.ObjectId(req.params.formIdNoMiddleware), + admin: mongoose.Types.ObjectId(req.user.id) + } + }, + { + $facet: { + "deviceStatistics": [ + { + $unwind: '$analytics.visitors' + }, + { + $project: { + _id: 0, + deviceType: '$analytics.visitors.deviceType', + SubmittedTimeElapsed: { + $cond: [ + { + $eq: ['$analytics.visitors.isSubmitted', true] + }, + '$analytics.visitors.timeElapsed', + 0 + ] + }, + SubmittedResponses: { + $cond: [ + { + $eq: ['$analytics.visitors.isSubmitted', true] + }, + 1, + 0 + ] + } + } + }, + { + $group: { + _id: "$deviceType", + total_time: { $sum: "$SubmittedTimeElapsed" }, + responses: { $sum: "$SubmittedResponses" }, + visits: { $sum: 1 } + } + }, + { + $project: { + total_time: "$total_time", + responses: "$responses", + visits: "$visits", + average_time: { + $divide : ["$total_time", "$responses"] + }, + conversion_rate: { + $divide : ["$responses", "$visits"] + } + } + } + ], + "globalStatistics": [ + { + $unwind: '$analytics.visitors' + }, + { + $project: { + _id: 0, + deviceType: '$analytics.visitors.deviceType', + SubmittedTimeElapsed: { + $cond: [ + { + $eq: ['$analytics.visitors.isSubmitted', true] + }, + '$analytics.visitors.timeElapsed', + 0 + ] + }, + SubmittedResponses: { + $cond: [ + { + $eq: ['$analytics.visitors.isSubmitted', true] + }, + 1, + 0 + ] + } + } + }, + { + $group: { + _id: null, + total_time: { $sum: "$SubmittedTimeElapsed" }, + responses: { $sum: "$SubmittedResponses" }, + visits: { $sum: 1 } + } + }, + { + $project: { + _id: 0, + total_time: "$total_time", + responses: "$responses", + visits: "$visits", + average_time: { + $divide : ["$total_time", "$responses"] + }, + conversion_rate: { + $divide : ["$responses", "$visits"] + } + } + } + ], + } + } + ], function(err, results){ + if (err) { + console.error(err); + return res.status(500).send({ + message: errorHandler.getErrorMessage(err) + }); + } + + return res.json(results); + }); +}; + + /** * Create a new form */ @@ -181,7 +310,7 @@ exports.read = function(req, res) { var newForm = req.form.toJSON(); - if(newForm.admin._id === req.user._id){ + if(newForm.admin === req.user._id){ return res.json(newForm); } @@ -323,6 +452,7 @@ exports.formByID = function(req, res, next, id) { } Form.findById(id) + .select('admin title language form_fields startPage endPage hideFooter isLive design analytics.gaCode') .populate('admin') .exec(function(err, form) { if (err) { diff --git a/app/models/form.server.model.js b/app/models/form.server.model.js index 7aaef85e..236d0ddd 100644 --- a/app/models/form.server.model.js +++ b/app/models/form.server.model.js @@ -8,13 +8,8 @@ var mongoose = require('mongoose'), _ = require('lodash'), timeStampPlugin = require('../libs/timestamp.server.plugin'), async = require('async'), - Random = require('random-js'), - mt = Random.engines.mt19937(), constants = require('../libs/constants'); - -mt.autoSeed(); - //Mongoose Models var FieldSchema = require('./form_field.server.model.js'); @@ -48,8 +43,8 @@ var VisitorDataSchema = new Schema({ referrer: { type: String }, - lastActiveField: { - type: Schema.Types.ObjectId + filledOutFields: { + type: [Schema.Types.ObjectId] }, timeElapsed: { type: Number @@ -112,7 +107,7 @@ var FormSchema = new Schema({ type: Schema.Types.ObjectId, ref: 'FormSubmission' }], - dfeault: [] + default: [] }, admin: { type: Schema.Types.ObjectId, @@ -239,94 +234,6 @@ var FormSchema = new Schema({ } }, formSchemaOptions); -/* -** In-Form Analytics Virtual Attributes - */ -FormSchema.virtual('analytics.views').get(function () { - if(this.analytics && this.analytics.visitors && this.analytics.visitors.length > 0){ - return this.analytics.visitors.length; - } else { - return 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; - } -}); - -FormSchema.virtual('analytics.fields').get(function () { - var fieldDropoffs = []; - var visitors = this.analytics.visitors; - var that = this; - - if(!this.form_fields || this.form_fields.length === 0) { - return null; - } - - for(var i=0; i i){ - return sum + 1; - } - return sum; - }, 0); - } else { - continueViews = _.reduce(visitors, function(sum, visitorObj){ - if(visitorObj.lastActiveField+'' === field._id+'' && visitorObj.isSubmitted){ - return sum + 1; - } - return sum; - }, 0); - - } - - 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, - totalViews: totalViews, - continueRate: continueRate, - dropoffRate: dropoffRate, - field: field - }; - - } - } - - return fieldDropoffs; -}); - FormSchema.plugin(timeStampPlugin, { createdPath: 'created', modifiedPath: 'lastModified', diff --git a/app/routes/forms.server.routes.js b/app/routes/forms.server.routes.js index fbb4335a..7d2e3e14 100644 --- a/app/routes/forms.server.routes.js +++ b/app/routes/forms.server.routes.js @@ -47,6 +47,8 @@ module.exports = function(app) { .get(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.listSubmissions) .delete(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.deleteSubmissions); + app.route('/forms/:formIdNoMiddleware([a-zA-Z0-9]+)/visitors') + .get(auth.isAuthenticatedOrApiKey, forms.getVisitorData); // Slower formId middleware app.param('formId', forms.formByID); diff --git a/app/sockets/analytics_service.js b/app/sockets/analytics_service.js index 993a0468..0021f60f 100644 --- a/app/sockets/analytics_service.js +++ b/app/sockets/analytics_service.js @@ -22,7 +22,6 @@ module.exports = function (io, socket) { var newVisitor = { socketId: data.socketId, referrer: data.referrer, - lastActiveField: data.lastActiveField, timeElapsed: data.timeElapsed, isSubmitted: data.isSubmitted, language: data.language, diff --git a/package-lock.json b/package-lock.json index 6538e5b6..ab46ade9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2710,6 +2710,11 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-0.4.23.tgz", "integrity": "sha1-5louPHUH/63kEJvHV1p25Q+NqRU=" }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -7035,9 +7040,9 @@ "integrity": "sha1-D1kbGzRL3LPfWXc/Yvu6+Fv0Aos=" }, "hooks-fixed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-1.1.0.tgz", - "integrity": "sha1-DowVM2cI5mERhf45C0RofdUjDbs=" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-2.0.2.tgz", + "integrity": "sha512-YurCM4gQSetcrhwEtpQHhQ4M7Zo7poNGqY4kQGeBS6eZtOcT3tnNs01ThFa0jYBByAiYt1MjMjP/YApG0EnAvQ==" }, "hosted-git-info": { "version": "2.5.0", @@ -8002,9 +8007,9 @@ } }, "kareem": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-1.0.1.tgz", - "integrity": "sha1-eAXSFbtTIU7Dr5aaHQsfF+PnuVw=" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-1.5.0.tgz", + "integrity": "sha1-4+QQHZ3P3imXadr0tNtk2JXRdEg=" }, "karma": { "version": "0.13.22", @@ -8690,6 +8695,11 @@ } } }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -9365,70 +9375,79 @@ } }, "mongoose": { - "version": "4.4.20", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.4.20.tgz", - "integrity": "sha1-6XT/tq6MUPQJgBqEl6mOnztR8t0=", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.13.0.tgz", + "integrity": "sha512-PVUEQ4eS1Bh0Q4IqWRph+li8VMwBxHetdJ1O/P/vE8DktOtBOM1G1G0QOrtQSW1FDrLFSVYkzK4IfI7vJeihQg==", "requires": { - "async": "1.5.2", - "bson": "0.4.23", - "hooks-fixed": "1.1.0", - "kareem": "1.0.1", - "mongodb": "2.1.18", - "mpath": "0.2.1", + "async": "2.1.4", + "bson": "1.0.4", + "hooks-fixed": "2.0.2", + "kareem": "1.5.0", + "lodash.get": "4.4.2", + "mongodb": "2.2.33", + "mpath": "0.3.0", "mpromise": "0.5.5", - "mquery": "1.11.0", - "ms": "0.7.1", - "muri": "1.1.0", + "mquery": "2.3.2", + "ms": "2.0.0", + "muri": "1.3.0", "regexp-clone": "0.0.1", "sliced": "1.0.1" }, "dependencies": { + "async": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", + "integrity": "sha1-LSFgx3iAMuTdbL4lAvH5osj2zeQ=", + "requires": { + "lodash": "4.17.4" + } + }, "bluebird": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz", - "integrity": "sha1-AkpVFylTCIV/FPkfEQb8O1VfRGs=" + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "bson": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz", + "integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw=" }, "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "ms": "0.7.1" + "ms": "2.0.0" } }, "es6-promise": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=" }, "mongodb": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.1.18.tgz", - "integrity": "sha1-KNQLUVsr5NWmn/3UxTXw30MuQJc=", + "version": "2.2.33", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.33.tgz", + "integrity": "sha1-tTfEcdNKZlG0jzb9vyl1A0Dgi1A=", "requires": { - "es6-promise": "3.0.2", - "mongodb-core": "1.3.18", - "readable-stream": "1.0.31" + "es6-promise": "3.2.1", + "mongodb-core": "2.1.17", + "readable-stream": "2.2.7" } }, "mongodb-core": { - "version": "1.3.18", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-1.3.18.tgz", - "integrity": "sha1-kGhLO3xzVtZa41Y5HTCw8kiATHo=", + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.17.tgz", + "integrity": "sha1-pBizN6FKFJkPtRC5I97mqBMXPfg=", "requires": { - "bson": "0.4.23", + "bson": "1.0.4", "require_optional": "1.0.1" } }, "mpath": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.2.1.tgz", - "integrity": "sha1-Ok6Ck1mAHeljCcJ6ay4QLon56W4=" + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.3.0.tgz", + "integrity": "sha1-elj3iem1/TyUUgY0FXlg8mvV70Q=" }, "mpromise": { "version": "0.5.5", @@ -9436,12 +9455,12 @@ "integrity": "sha1-9bJCWddjrMIlewoMjG2Gb9UXMuY=" }, "mquery": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-1.11.0.tgz", - "integrity": "sha1-4MZd7bEDftv2z7iCYud3/uI1Udk=", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-2.3.2.tgz", + "integrity": "sha512-KXWMypZSvhCuqRtza+HMQZdYw7PfFBjBTFvP31NNAq0OX0/NTIgpcDpkWQ2uTxk6vGQtwQ2elhwhs+ZvCA8OaA==", "requires": { - "bluebird": "2.10.2", - "debug": "2.2.0", + "bluebird": "3.5.1", + "debug": "2.6.9", "regexp-clone": "0.0.1", "sliced": "0.0.5" }, @@ -9453,31 +9472,29 @@ } } }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + "muri": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/muri/-/muri-1.3.0.tgz", + "integrity": "sha512-FiaFwKl864onHFFUV/a2szAl7X0fxVlSKNdhTf+BM8i8goEgYut8u5P9MqQqIYwvaMxjzVESsoEm/2kfkFH1rg==" }, "readable-stream": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", - "integrity": "sha1-jyUC4LyeOw2huUUgqrtOJgPsr64=", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", + "integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE=", "requires": { + "buffer-shims": "1.0.0", "core-util-is": "1.0.2", "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" } } }, diff --git a/package.json b/package.json index 8e83b6eb..5f3ba4c4 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "generate": "all-contributors generate", "start": "grunt", "test": "grunt test", + "postinstall": "bower install --config.interactive=false", "travis": "grunt test:travis", - "postinstall": "bower install --config.interactive=false; grunt build;", "init": "node scripts/setup.js" }, "dependencies": { @@ -58,7 +58,7 @@ "main-bower-files": "~2.9.0", "method-override": "~2.3.0", "mkdirp": "^0.5.1", - "mongoose": "~4.4.19", + "mongoose": "^4.13.0", "morgan": "~1.8.1", "nodemailer": "~4.0.0", "passport": "~0.3.0", @@ -86,7 +86,6 @@ "grunt-closure-compiler": "0.0.21", "grunt-contrib-concat": "^1.0.1", "grunt-contrib-copy": "^1.0.0", - "grunt-contrib-uglify": "^0.11.1", "grunt-contrib-watch": "~0.6.1", "grunt-execute": "^0.2.2", "grunt-karma": "~0.12.1", diff --git a/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js b/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js index e405da62..314a2a77 100644 --- a/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js +++ b/public/modules/forms/admin/directives/edit-submissions-form.client.directive.js @@ -14,6 +14,10 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope', masterChecker: false, rows: [] }; + $scope.analyticsData = { + deviceStatistics: [], + globalStatistics: [] + }; $scope.deletionInProgress = false; $scope.waitingForDeletion = false; @@ -73,11 +77,11 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope', method: 'GET', url: '/forms/'+$scope.myform._id+'/visitors' }).then(function successCallback(response) { - var defaultFormFields = _.cloneDeep($scope.myform.form_fields); + var data = response.data || []; - var visitors = response.data || []; - - $scope.visitors = visitors; + $scope.analyticsData = data[0]; + $scope.analyticsData.globalStatistics = $scope.analyticsData.globalStatistics[0]; + $scope.analyticsData.deviceStatistics = formatDeviceStatistics($scope.analyticsData.deviceStatistics); }); }; @@ -102,26 +106,12 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope', /* ** Analytics Functions */ - $scope.AverageTimeElapsed = (function(){ - var totalTime = 0; - var numSubmissions = $scope.table.rows.length; - - for(var i=0; i<$scope.table.rows.length; i++){ - totalTime += $scope.table.rows[i].timeElapsed; - } - - if(numSubmissions === 0) { - return 0; - } - return (totalTime/numSubmissions).toFixed(0); - })(); - - $scope.DeviceStatistics = (function(){ + var formatDeviceStatistics = function(deviceStatData){ var newStatItem = function(){ return { visits: 0, responses: 0, - completion: 0, + conversion_rate: 0, average_time: 0, total_time: 0 }; @@ -134,30 +124,16 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope', 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); + if(deviceStatData.length){ + for(var i=0; i
- {{myform.analytics.visitors.length}} + {{analyticsData.globalStatistics.visits | number:0}}
- {{myform.analytics.submissions}} + {{analyticsData.globalStatistics.responses | number:0}}
- {{myform.analytics.conversionRate | number:0}}% + {{analyticsData.globalStatistics.conversion_rate | number:2}}
- {{ AverageTimeElapsed | secondsToDateTime | date:'mm:ss'}} + {{analyticsData.globalStatistics.average_time | secondsToDateTime | date:'mm:ss'}}
@@ -58,7 +58,7 @@ {{ 'UNIQUE_VISITS' | translate }}
- {{DeviceStatistics.desktop.visits}} + {{analyticsData.deviceStatistics.desktop.visits | number:0}}
@@ -67,7 +67,7 @@ {{ 'UNIQUE_VISITS' | translate }}
- {{DeviceStatistics.tablet.visits}} + {{analyticsData.deviceStatistics.tablet.visits | number:0}}
@@ -76,7 +76,7 @@ {{ 'UNIQUE_VISITS' | translate }}
- {{DeviceStatistics.tablet.visits}} + {{analyticsData.deviceStatistics.tablet.visits | number:0}}
@@ -85,7 +85,7 @@ {{ 'UNIQUE_VISITS' | translate }}
- {{DeviceStatistics.other.visits}} + {{analyticsData.deviceStatistics.other.visits | number:0}}
@@ -96,7 +96,7 @@ {{ 'RESPONSES' | translate }}
- {{DeviceStatistics.desktop.responses}} + {{analyticsData.deviceStatistics.desktop.responses | number:0}}
@@ -105,7 +105,7 @@ {{ 'RESPONSES' | translate }}
- {{DeviceStatistics.tablet.responses}} + {{analyticsData.deviceStatistics.tablet.responses | number:0}}
@@ -114,7 +114,7 @@ {{ 'RESPONSES' | translate }}
- {{DeviceStatistics.phone.responses}} + {{analyticsData.deviceStatistics.phone.responses | number:0}}
@@ -123,7 +123,7 @@ {{ 'RESPONSES' | translate }}
- {{DeviceStatistics.other.responses}} + {{analyticsData.deviceStatistics.other.responses | number:0}}
@@ -134,7 +134,7 @@ {{ 'COMPLETION_RATE' | translate }}
- {{DeviceStatistics.desktop.completion}}% + {{analyticsData.deviceStatistics.desktop.conversion_rate | number:2}}%
@@ -143,7 +143,7 @@ {{ 'COMPLETION_RATE' | translate }}
- {{DeviceStatistics.tablet.completion}}% + {{analyticsData.deviceStatistics.tablet.conversion_rate | number:2}}%
@@ -152,7 +152,7 @@ {{ 'COMPLETION_RATE' | translate }}
- {{DeviceStatistics.phone.completion}}% + {{analyticsData.deviceStatistics.phone.conversion_rate | number:2}}%
@@ -161,7 +161,7 @@ {{ 'COMPLETION_RATE' | translate }}
- {{DeviceStatistics.other.completion}}% + {{analyticsData.deviceStatistics.other.conversion_rate | number:2}}%
@@ -172,7 +172,7 @@ {{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
- {{DeviceStatistics.desktop.average_time | secondsToDateTime | date:'mm:ss'}} + {{analyticsData.deviceStatistics.desktop.average_time | secondsToDateTime | date:'mm:ss'}}
@@ -181,7 +181,7 @@ {{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
- {{DeviceStatistics.tablet.average_time | secondsToDateTime | date:'mm:ss'}} + {{analyticsData.deviceStatistics.tablet.average_time | secondsToDateTime | date:'mm:ss'}}
@@ -190,7 +190,7 @@ {{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
- {{DeviceStatistics.phone.average_time | secondsToDateTime | date:'mm:ss'}} + {{analyticsData.deviceStatistics.phone.average_time | secondsToDateTime | date:'mm:ss'}}
@@ -199,11 +199,12 @@ {{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
- {{DeviceStatistics.other.average_time | secondsToDateTime | date:'mm:ss'}} + {{analyticsData.deviceStatistics.other.average_time | secondsToDateTime | date:'mm:ss'}}
+ + +