From d936383cd2e888f1c5a275998ba38f445d8d2b65 Mon Sep 17 00:00:00 2001 From: James Warren Date: Mon, 27 Jul 2015 16:00:26 +0100 Subject: [PATCH 1/5] initial users stats layout --- app/js/api/factories/UsersResource.js | 6 + app/js/app.js | 1 + app/js/users/controllers/UserStatsCtrl.js | 218 ++++++++++++++++++++++ app/js/users/users.js | 8 + app/less/default/core/variables.less | 13 ++ app/less/default/modules/navs.less | 21 +++ app/less/default/modules/profile.less | 33 ++++ app/less/main.less | 3 + app/partials/user-stats.html | 135 ++++++++++++++ scripts.json | 3 + 10 files changed, 441 insertions(+) create mode 100644 app/js/users/controllers/UserStatsCtrl.js create mode 100644 app/js/users/users.js create mode 100644 app/less/default/modules/navs.less create mode 100644 app/less/default/modules/profile.less create mode 100644 app/partials/user-stats.html diff --git a/app/js/api/factories/UsersResource.js b/app/js/api/factories/UsersResource.js index 6e010381..50f490d8 100644 --- a/app/js/api/factories/UsersResource.js +++ b/app/js/api/factories/UsersResource.js @@ -25,6 +25,12 @@ angular.module("FM.api.UsersResource",[ // Default values for url parameters. { id: "@id" + }, + { + stats: { + method: "GET", + url: env.FM_API_SERVER_ADDRESS + "users" + "/:id/stats" + } } ); diff --git a/app/js/app.js b/app/js/app.js index 68b807f4..ed512b56 100644 --- a/app/js/app.js +++ b/app/js/app.js @@ -19,6 +19,7 @@ angular.module("FM", [ "FM.loadingScreen", "FM.nav", "FM.stats", + "FM.users", "ngRoute", "notification", "config" diff --git a/app/js/users/controllers/UserStatsCtrl.js b/app/js/users/controllers/UserStatsCtrl.js new file mode 100644 index 00000000..da238179 --- /dev/null +++ b/app/js/users/controllers/UserStatsCtrl.js @@ -0,0 +1,218 @@ +"use strict"; +/** + * @module FM.users.UserStatsCtrl + * @author SOON_ + */ +angular.module("FM.users.UserStatsCtrl", [ + "FM.api.UsersResource", + "FM.stats", + "ngMockE2E" + +]) +.run(["$httpBackend", function ($httpBackend) { + var stats = {"most_played_tracks": [{"track": {"album": {"id": "0fad2b5a-e947-4d2a-81e5-f1df52389895", "spotify_uri": "spotify:album:0BFzNaeaNv4mahOzwZFGHK", "name": "Royal Blood"}, "name": "Figure It Out", "spotify_uri": "spotify:track:3MjrueDQKVr6xDDseZwhEd", "artists": [], "duration": 184053, "id": "32edd7b4-7f5d-42e3-8a0e-0b54c9f02d15"}, "total": 6}, {"track": {"album": {"id": "a1da5909-3431-4154-b412-27bee155fb59", "spotify_uri": "spotify:album:6Clg4KBsvQUwCxf9dADoIt", "name": "Crying Lightning"}, "name": "Red Right Hand", "spotify_uri": "spotify:track:4eMHHSB98QBxOECsXInbxv", "artists": [], "duration": 259813, "id": "6bd3aa37-9916-43d4-a66a-29c762f4052f"}, "total": 4}, {"track": {"album": {"id": "78cad758-bd0b-4d8b-8dd5-5ca8a5bc76ae", "spotify_uri": "spotify:album:1XOSDyhzUmOFrp3ChmYFKO", "name": "Ship To Wreck"}, "name": "Ship To Wreck", "spotify_uri": "spotify:track:6WFpbFOV9q3Aa1I9tegWNN", "artists": [], "duration": 234526, "id": "fec6875e-a58d-4616-bdb6-4984a93a404d"}, "total": 3}, {"track": {"album": {"id": "26a21322-8495-4444-94f0-f016cf2daf24", "spotify_uri": "spotify:album:4AZpJ7WG1RFcimSggc05ZC", "name": "The Warning"}, "name": "Over And Over", "spotify_uri": "spotify:track:6m5D7zGVbzAxceDXQTsRSX", "artists": [], "duration": 347880, "id": "3b227506-cdac-4495-9799-cc5bd85697b5"}, "total": 3}, {"track": {"album": {"id": "3d78823d-b4d4-4a44-8a08-dec210d8a229", "spotify_uri": "spotify:album:26Bm3PBTkGz1eIMzXsfc6g", "name": "Ritual"}, "name": "Turn The Bells", "spotify_uri": "spotify:track:1ZMPQa4U9Sx7HZna41kvpS", "artists": [], "duration": 304093, "id": "5a0b7624-43ff-4761-b30f-792ff8101e6e"}, "total": 3}, {"track": {"album": {"id": "1d3f6c97-2a68-4ddb-9959-fd2463e85543", "spotify_uri": "spotify:album:2wart5Qjnvx1fd7LPdQxgJ", "name": "Drones"}, "name": "The Globalist - Premium Only", "spotify_uri": "spotify:track:6BGxbBw5J314z6BDxbEanm", "artists": [], "duration": 607282, "id": "4ee0bbe4-4895-44d3-8025-eeb5d89596e9"}, "total": 3}, {"track": {"album": {"id": "71b5c930-1936-47e3-b13e-8273ebe4200d", "spotify_uri": "spotify:album:7x7oLEHfjiYLzLHS93G1lr", "name": "Little Black Submarines"}, "name": "Little Black Submarines - radio edit", "spotify_uri": "spotify:track:17609ifVvJ7Npd8IqVnRFc", "artists": [], "duration": 204692, "id": "9143e2e6-7695-4918-98d4-9edfbd78d2ac"}, "total": 3}, {"track": {"album": {"id": "132e8bfb-7f1c-4457-98ca-41c3867ad98d", "spotify_uri": "spotify:album:76FdMKQqoDqPf95j5vq1AJ", "name": "Why Make Sense?"}, "name": "Huarache Lights", "spotify_uri": "spotify:track:6awtKwZBUZQzBFuqxjLsjO", "artists": [], "duration": 329169, "id": "68bc5bf0-d299-41d5-be66-94be78aab599"}, "total": 2}, {"track": {"album": {"id": "562b4369-9127-4223-af2a-3021981bf5f1", "spotify_uri": "spotify:album:25irJgxRNTlyg8pUmWfDVG", "name": "Greatest Hits"}, "name": "Homeward Bound", "spotify_uri": "spotify:track:1WCx3vqkBSPhwDz584C9tk", "artists": [], "duration": 162173, "id": "df8bdcf1-008d-48b6-b306-41ad25336368"}, "total": 2}, {"track": {"album": {"id": "3d78823d-b4d4-4a44-8a08-dec210d8a229", "spotify_uri": "spotify:album:26Bm3PBTkGz1eIMzXsfc6g", "name": "Ritual"}, "name": "Bad Love", "spotify_uri": "spotify:track:6IyNytssOakxZyyhef8Rmj", "artists": [], "duration": 237920, "id": "b1bd98a0-323b-43cd-a69e-587c09d0f3ff"}, "total": 2}], "total_plays": 215, "total_play_time": 57697107, "most_played_genres": [{"total": 63, "name": "rock"}, {"total": 55, "name": "indie rock"}, {"total": 53, "name": "permanent wave"}, {"total": 38, "name": "indietronica"}, {"total": 33, "name": "folk-pop"}, {"total": 31, "name": "new rave"}, {"total": 29, "name": "indie folk"}, {"total": 26, "name": "chamber pop"}, {"total": 25, "name": "piano rock"}, {"total": 25, "name": "indie pop"}], "most_played_artists": [{"total": 24, "artist": {"id": "ec32ec9e-6c15-4a6b-8a66-a1f4a86ed31c", "uri": "spotify:artist:12Chz98pHFMPJEknJQMWvI", "name": "Muse"}}, {"total": 9, "artist": {"id": "d01f6913-264f-40b6-9018-7a26c7fc7537", "uri": "spotify:artist:023YMawCG3OvACmRjWxLWC", "name": "The Cat Empire"}}, {"total": 9, "artist": {"id": "d2a9b543-7fa0-4438-b44a-1c32114dbceb", "uri": "spotify:artist:6ssXMmc5EOUrauZxirM910", "name": "White Lies"}}, {"total": 8, "artist": {"id": "ccf27755-ca07-4421-bc9f-5a7fa00b8624", "uri": "spotify:artist:6fBF4MULW5yMzyGaon1kUt", "name": "John Butler Trio"}}, {"total": 8, "artist": {"id": "8b292f2f-95cd-4a5c-9fa4-295ea5ab012d", "uri": "spotify:artist:7sjttK1WcZeyLPn3IsQ62L", "name": "Noel Gallagher's High Flying Birds"}}, {"total": 8, "artist": {"id": "d8ac4824-32b6-48c7-8ab5-1a0540d8ff51", "uri": "spotify:artist:3pTE9iaJTkWns3mxpNQlJV", "name": "Bombay Bicycle Club"}}, {"total": 7, "artist": {"id": "cb141ddf-4764-40c8-a368-1f0246b883fe", "uri": "spotify:artist:7Ln80lUS6He07XvHI8qqHH", "name": "Arctic Monkeys"}}, {"total": 7, "artist": {"id": "fa5bacd8-8631-4e40-83dc-32eb94a047ff", "uri": "spotify:artist:37uLId6Z5ZXCx19vuruvv5", "name": "Hot Chip"}}, {"total": 7, "artist": {"id": "fcb3373b-b5bc-4305-aa2d-b4ff60791fc6", "uri": "spotify:artist:5schNIzWdI9gJ1QRK8SBnc", "name": "Ben Howard"}}, {"total": 7, "artist": {"id": "4b4a124d-fd96-45b7-9fb5-e174e2369b26", "uri": "spotify:artist:7mnBLXK823vNxN3UWB7Gfz", "name": "The Black Keys"}}]}; + + $httpBackend.whenGET(/.*users\/.*\/stats.*/).respond(200, stats); + $httpBackend.whenGET(/.*users\/.*/).respond(200, { "avatar_url": "https://lh6.googleusercontent.com/-WOwGfU-QYjE/AAAAAAAAAAI/AAAAAAAAABE/lqC4XiCND18/photo.jpg", "display_name": "James Warren", "family_name": "Warren", "given_name": "James", "id": "785bc064-0e08-4ea3-98d5-446e497bd213", "spotify_playlists": null }); + $httpBackend.whenGET(/.*/).passThrough(); +}]) +/** + * @method config + * @param {Provider} $routeProvider + */ +.config([ + "$routeProvider", + function ($routeProvider) { + + $routeProvider + .when("/users/:id", { + templateUrl: "partials/user-stats.html", + controller: "UserStatsCtrl", + resolve: { + stats: ["UsersResource", "$route", function (UsersResource, $route){ + return UsersResource.stats($route.current.params).$promise; + }], + user: ["UsersResource", "$route", function (UsersResource, $route){ + return UsersResource.get($route.current.params).$promise; + }] + } + }); + + } +]) +/** + * @constructor + * @class UserStatsCtrl + * @param {Object} $scope Scoped application data + * @param {Service} $q Angular promise service + * @param {Service} $filter Angular filter service + * @param {Service} $location Angular URL service + * @param {Object} stats User's stats resolved from API + * @param {Array} CHART_COLOURS List of global chart colours + * @param {Object} CHART_OPTIONS ChartJS config options + */ +.controller("UserStatsCtrl", [ + "$scope", + "$q", + "$filter", + "$location", + "stats", + "user", + "CHART_COLOURS", + "CHART_OPTIONS", + "UsersResource", + function ($scope, $q, $filter, $location, stats, user, CHART_COLOURS, CHART_OPTIONS, UsersResource) { + + /** + * User + * @property {Object} user + */ + $scope.user = user; + + /** + * User's stats resolved from API + * @property {Object} stats + */ + $scope.stats = stats; + + /** + * Current search params + * @property {Object} search + */ + $scope.search = $location.search(); + + /** + * @property {Object} filter + */ + $scope.filter = {}; + + /** + * Track open status of datepickers + * @property {Object} datepickerOpened + */ + $scope.datepickerOpened = { + from: "", + to: "" + }; + + /** + * List of colours to use for charts + * @property {Array} chartColours + */ + $scope.chartColours = CHART_COLOURS; + + /** + * ChartJS config for play time line graph + * @property {Object} playTime + */ + $scope.playTime = { + data: [[]], + series: [user.display_name], + labels: [], + options: CHART_OPTIONS + }; + + /** + * Load historic play time statistics for line chart based on filter start/end dates + * @method loadHistoricData + * @param {String} startDate Filter start date + * @param {String} endDate Filter end date + */ + $scope.loadHistoricData = function loadHistoricData (startDate, endDate) { + + startDate = new Date(startDate); + endDate = endDate ? new Date(endDate) : new Date(); + + /** + * Difference in days between filter start and end dates + * @property {Number} diff + */ + var diff = (startDate.getTime() - endDate.getTime()) / (24 * 60 * 60 * 1000); + + /** + * Calculated dates for historic data, based on filter dates + * Eg. if the filter period is 1 week this will be 1 week before, 2 weeks before and 3 weeks before + * @property {Array} dates + */ + var dates = [{ + from: $filter("date")(new Date().setDate(startDate.getDate() + diff), "yyyy-MM-dd"), + to: $filter("date")(new Date().setDate(startDate.getDate() - 1), "yyyy-MM-dd"), + },{ + from: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 2)), "yyyy-MM-dd"), + to: $filter("date")(new Date().setDate(startDate.getDate() + (diff) - 1), "yyyy-MM-dd"), + },{ + from: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 3)), "yyyy-MM-dd"), + to: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 2) - 1), "yyyy-MM-dd"), + }]; + + // request historic data from API using calculated date ranges + $q.all([ + UsersResource.stats({ from: dates[0].from, to: dates[0].to, id: user.id }).$promise, + UsersResource.stats({ from: dates[1].from, to: dates[1].to, id: user.id }).$promise, + UsersResource.stats({ from: dates[2].from, to: dates[2].to, id: user.id }).$promise + ]).then(function (responses) { + responses.forEach(function (response, index) { + // add data to play time chart dataset + $scope.playTime.labels.unshift($filter("date")(dates[index].from, "dd-MM-yyyy")); + // convert milliseconds to minutes + $scope.playTime.data[0].unshift(Math.round(response.total_play_time / 1000 / 60)); + }); + }); + }; + + /** + * Filter stats by dates + * @method updateFilter + */ + $scope.updateFilter = function updateFilter () { + if ($scope.filter.to) { + $scope.search.to = $scope.filter.to.toISOString ? $filter("date")($scope.filter.to.toISOString(), "yyyy-MM-dd") : $scope.filter.to; + } else { + $scope.search.to = undefined; + } + if ($scope.filter.from) { + $scope.search.from = $scope.filter.from.toISOString ? $filter("date")($scope.filter.from.toISOString(), "yyyy-MM-dd") : $scope.filter.from; + } else { + $scope.search.from = undefined; + $scope.search.all = true; + } + $location.search($scope.search); + }; + + /** + * Open datepicker + * @method updateFilter + */ + $scope.openDatepicker = function openDatepicker($event, id) { + $event.preventDefault(); + $event.stopPropagation(); + $scope.datepickerOpened[id] = !$scope.datepickerOpened[id] ; + }; + + /** + * Set current filter params and load historic data on initalise + * @method init + */ + $scope.init = function init () { + + $scope.filter.from = $scope.search.from || undefined; + $scope.filter.to = $scope.search.to || undefined; + + // set max datepicker date to today + $scope.datepickerMaxDate = new Date(); + + if ($scope.filter.from) { + // Format total play time per user stats for charts + $scope.playTime.labels.unshift($filter("date")($scope.filter.from, "dd-MM-yyyy")); + // convert milliseconds to minutes + $scope.playTime.data[0].unshift(Math.round(stats.total_play_time / 1000 / 60)); + + // Load additional data for play time line chart + $scope.loadHistoricData($scope.filter.from, $scope.filter.to); + } + }; + + $scope.init(); + + } +]); diff --git a/app/js/users/users.js b/app/js/users/users.js new file mode 100644 index 00000000..dd07d976 --- /dev/null +++ b/app/js/users/users.js @@ -0,0 +1,8 @@ +"use strict"; +/** + * @module FM.users + * @author SOON_ + */ +angular.module("FM.users", [ + "FM.users.UserStatsCtrl" +]); diff --git a/app/less/default/core/variables.less b/app/less/default/core/variables.less index 467c1123..8b667f47 100644 --- a/app/less/default/core/variables.less +++ b/app/less/default/core/variables.less @@ -171,6 +171,19 @@ //** Element ID within SVG icon file. @icon-font-svg-id: "icomoon"; +//== Navs +// +//## + +//=== Shared nav styles +@nav-link-hover-bg: @lighter-black; + +//== Tabs +@nav-tabs-border-color: @lighter-black; +@nav-tabs-link-hover-border-color: @lighter-black; +@nav-tabs-active-link-hover-bg: @lighter-black; +@nav-tabs-active-link-hover-color: @lighter-black; + //== Popovers // //## diff --git a/app/less/default/modules/navs.less b/app/less/default/modules/navs.less new file mode 100644 index 00000000..ce62bdb8 --- /dev/null +++ b/app/less/default/modules/navs.less @@ -0,0 +1,21 @@ +// +// Navs +// -------------------------------------------------- + + +// Tabs +.nav-tabs { + margin-bottom: 20px; +} + +.nav-tabs > li > a { + border-radius: 0; +} + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + border: none; + border-bottom: 2px solid @brand-primary; + color: @white; +} diff --git a/app/less/default/modules/profile.less b/app/less/default/modules/profile.less new file mode 100644 index 00000000..8849b342 --- /dev/null +++ b/app/less/default/modules/profile.less @@ -0,0 +1,33 @@ +// +// Profile +// -------------------------------------------------- + +.profile { + .flex-box(); + .align-items(stretch); + .flex-direction(row); + .flex-wrap(nowrap); + .justify-content(flex-start); + margin-top: 20px; + margin-bottom: 40px; + + .avatar { + .flex(3); + .align-self(center); + + img { + .img-responsive(); + .img-circle(); + } + } + + .name { + .flex(9); + .align-self(center); + margin-left: @grid-gutter-width * 2; + + h1 { + margin: 0; + } + } +} diff --git a/app/less/main.less b/app/less/main.less index 4b35c12b..1f8ee133 100644 --- a/app/less/main.less +++ b/app/less/main.less @@ -37,6 +37,7 @@ @import "@{bootstrap-less}thumbnails.less"; @import "@{bootstrap-less}badges.less"; @import "@{bootstrap-less}media.less"; +@import "@{bootstrap-less}navs.less"; // Utility classes @import "@{bootstrap-less}utilities.less"; @@ -68,6 +69,8 @@ @import "default/modules/progress.less"; @import "default/modules/stats.less"; @import "default/modules/media.less"; +@import "default/modules/navs.less"; +@import "default/modules/profile.less"; // Import less files for large screen devices here diff --git a/app/partials/user-stats.html b/app/partials/user-stats.html new file mode 100644 index 00000000..3244695a --- /dev/null +++ b/app/partials/user-stats.html @@ -0,0 +1,135 @@ +
+
+ {{ user.display_name }} +
+
+

{{ user.display_name }}

+
+
+ + + + +
+ +
+
+
+
+
+ + + + +
+
+
+
+ + + + +
+
+
+ +
+
+ +
+ +
+
+

{{ stats.total_plays }}

+

Total Tracks Played

+
+
+

{{ stats.total_play_time | time }}

+

Total Play Time

+
+
+ +
+
+ + + +

Play Time

+

Set filter dates to view historic play time from previous periods

+ +
+
+
+ +
+ +
+ +

Top Tracks

+ +
    +
  • +
  • +
+
+ +
+ +
+ +
+ +

Top Artists

+ + +
+ +
+ +

Top Genres

+ +
    +
  • +

    {{$index + 1}}.

    +

    {{ genre.name }}

    +

    {{ genre.total }} plays

    +
  • +
+
+ +
+
diff --git a/scripts.json b/scripts.json index 600b1f83..a76dd1b1 100644 --- a/scripts.json +++ b/scripts.json @@ -71,6 +71,9 @@ "./app/js/stats/services/DateUtils.js", "./app/js/stats/services/StatsResolver.js", + "./app/js/users/users.js", + "./app/js/users/controllers/UserStatsCtrl.js", + "./app/js/nav/nav.js", "./app/js/app.js" From b87e46cc3da55544817a0b8d3ecc35287f089c69 Mon Sep 17 00:00:00 2001 From: James Warren Date: Mon, 27 Jul 2015 16:25:04 +0100 Subject: [PATCH 2/5] move historic date period calculation to DateUtils service --- app/js/stats/controllers/StatsCtrl.js | 25 +---------- app/js/stats/services/DateUtils.js | 40 ++++++++++++++++- app/js/users/controllers/UserStatsCtrl.js | 55 ++++++++--------------- tests/unit/stats/services/DateUtils.js | 25 +++++++++++ 4 files changed, 83 insertions(+), 62 deletions(-) diff --git a/app/js/stats/controllers/StatsCtrl.js b/app/js/stats/controllers/StatsCtrl.js index 1ba1dd7b..395d3f7e 100644 --- a/app/js/stats/controllers/StatsCtrl.js +++ b/app/js/stats/controllers/StatsCtrl.js @@ -142,30 +142,7 @@ angular.module("FM.stats.StatsCtrl", [ */ $scope.loadHistoricData = function loadHistoricData (startDate, endDate) { - startDate = new Date(startDate); - endDate = endDate ? new Date(endDate) : new Date(); - - /** - * Difference in days between filter start and end dates - * @property {Number} diff - */ - var diff = (startDate.getTime() - endDate.getTime()) / (24 * 60 * 60 * 1000); - - /** - * Calculated dates for historic data, based on filter dates - * Eg. if the filter period is 1 week this will be 1 week before, 2 weeks before and 3 weeks before - * @property {Array} dates - */ - var dates = [{ - from: $filter("date")(new Date().setDate(startDate.getDate() + diff), "yyyy-MM-dd"), - to: $filter("date")(new Date().setDate(startDate.getDate() - 1), "yyyy-MM-dd"), - },{ - from: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 2)), "yyyy-MM-dd"), - to: $filter("date")(new Date().setDate(startDate.getDate() + (diff) - 1), "yyyy-MM-dd"), - },{ - from: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 3)), "yyyy-MM-dd"), - to: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 2) - 1), "yyyy-MM-dd"), - }]; + var dates = DateUtils.historicDatePeriods(startDate, endDate, 3); // request historic data from API using calculated date ranges $q.all([ diff --git a/app/js/stats/services/DateUtils.js b/app/js/stats/services/DateUtils.js index 340313c7..4cab989a 100644 --- a/app/js/stats/services/DateUtils.js +++ b/app/js/stats/services/DateUtils.js @@ -26,8 +26,9 @@ angular.module("FM.stats.DateUtils", [ * @returns {Object} */ .service("DateUtils", [ + "$filter", "LAST_WEEK", - function (LAST_WEEK) { + function ($filter, LAST_WEEK) { /** * Return last occurence of a day in the week @@ -42,5 +43,42 @@ angular.module("FM.stats.DateUtils", [ } }; + /** + * Return previous date periods from date range + * E.g. given this week as a date range this will return last week, two weeks ago, three weeks ago etc + * @method historicDatePeriods + * @param {Date} startDate + * @param {Date} endDate + * @param {Number} numberOfPeriods + */ + this.historicDatePeriods = function historicDatePeriods (startDate, endDate, numberOfPeriods) { + + startDate = new Date(startDate); + endDate = endDate ? new Date(endDate) : new Date(); + + /** + * Difference in days between filter start and end dates + * @property {Number} diff + */ + var diff = (startDate.getTime() - endDate.getTime()) / (24 * 60 * 60 * 1000); + + /** + * Calculated dates for historic data, based on filter dates + * Eg. if the filter period is 1 week this will be 1 week before, 2 weeks before and 3 weeks before + * @property {Array} dates + */ + var dates = []; + + for (var i = 1; i <= numberOfPeriods; i++) { + dates.push({ + from: $filter("date")(new Date().setDate(startDate.getDate() + (diff * i)), "yyyy-MM-dd"), + to: $filter("date")(new Date().setDate(startDate.getDate() + (diff * (i - 1)) - 1), "yyyy-MM-dd"), + }); + } + + return dates; + + }; + } ]); diff --git a/app/js/users/controllers/UserStatsCtrl.js b/app/js/users/controllers/UserStatsCtrl.js index da238179..021e4373 100644 --- a/app/js/users/controllers/UserStatsCtrl.js +++ b/app/js/users/controllers/UserStatsCtrl.js @@ -43,25 +43,29 @@ angular.module("FM.users.UserStatsCtrl", [ /** * @constructor * @class UserStatsCtrl - * @param {Object} $scope Scoped application data - * @param {Service} $q Angular promise service - * @param {Service} $filter Angular filter service - * @param {Service} $location Angular URL service - * @param {Object} stats User's stats resolved from API - * @param {Array} CHART_COLOURS List of global chart colours - * @param {Object} CHART_OPTIONS ChartJS config options + * @param {Object} $scope Scoped application data + * @param {Service} $q Angular promise service + * @param {Service} $filter Angular filter service + * @param {Service} $location Angular URL service + * @param {Service} DateUtils Date helper functions + * @param {Array} CHART_COLOURS List of global chart colours + * @param {Object} CHART_OPTIONS ChartJS config options + * @param {Resource} StatsResource Provides communication with stats API endpoint + * @param {Object} stats User's stats resolved from API + * @param {Object} user User object resolved from API */ .controller("UserStatsCtrl", [ "$scope", "$q", "$filter", "$location", - "stats", - "user", + "DateUtils", "CHART_COLOURS", "CHART_OPTIONS", "UsersResource", - function ($scope, $q, $filter, $location, stats, user, CHART_COLOURS, CHART_OPTIONS, UsersResource) { + "stats", + "user", + function ($scope, $q, $filter, $location, DateUtils, CHART_COLOURS, CHART_OPTIONS, UsersResource, stats, user) { /** * User @@ -107,7 +111,7 @@ angular.module("FM.users.UserStatsCtrl", [ */ $scope.playTime = { data: [[]], - series: [user.display_name], + series: [user.display_name], // jshint ignore:line labels: [], options: CHART_OPTIONS }; @@ -120,30 +124,7 @@ angular.module("FM.users.UserStatsCtrl", [ */ $scope.loadHistoricData = function loadHistoricData (startDate, endDate) { - startDate = new Date(startDate); - endDate = endDate ? new Date(endDate) : new Date(); - - /** - * Difference in days between filter start and end dates - * @property {Number} diff - */ - var diff = (startDate.getTime() - endDate.getTime()) / (24 * 60 * 60 * 1000); - - /** - * Calculated dates for historic data, based on filter dates - * Eg. if the filter period is 1 week this will be 1 week before, 2 weeks before and 3 weeks before - * @property {Array} dates - */ - var dates = [{ - from: $filter("date")(new Date().setDate(startDate.getDate() + diff), "yyyy-MM-dd"), - to: $filter("date")(new Date().setDate(startDate.getDate() - 1), "yyyy-MM-dd"), - },{ - from: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 2)), "yyyy-MM-dd"), - to: $filter("date")(new Date().setDate(startDate.getDate() + (diff) - 1), "yyyy-MM-dd"), - },{ - from: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 3)), "yyyy-MM-dd"), - to: $filter("date")(new Date().setDate(startDate.getDate() + (diff * 2) - 1), "yyyy-MM-dd"), - }]; + var dates = DateUtils.historicDatePeriods(startDate, endDate, 3); // request historic data from API using calculated date ranges $q.all([ @@ -155,7 +136,7 @@ angular.module("FM.users.UserStatsCtrl", [ // add data to play time chart dataset $scope.playTime.labels.unshift($filter("date")(dates[index].from, "dd-MM-yyyy")); // convert milliseconds to minutes - $scope.playTime.data[0].unshift(Math.round(response.total_play_time / 1000 / 60)); + $scope.playTime.data[0].unshift(Math.round(response.total_play_time / 1000 / 60)); // jshint ignore:line }); }); }; @@ -205,7 +186,7 @@ angular.module("FM.users.UserStatsCtrl", [ // Format total play time per user stats for charts $scope.playTime.labels.unshift($filter("date")($scope.filter.from, "dd-MM-yyyy")); // convert milliseconds to minutes - $scope.playTime.data[0].unshift(Math.round(stats.total_play_time / 1000 / 60)); + $scope.playTime.data[0].unshift(Math.round(stats.total_play_time / 1000 / 60)); // jshint ignore:line // Load additional data for play time line chart $scope.loadHistoricData($scope.filter.from, $scope.filter.to); diff --git a/tests/unit/stats/services/DateUtils.js b/tests/unit/stats/services/DateUtils.js index a8f95c74..ae44f79f 100644 --- a/tests/unit/stats/services/DateUtils.js +++ b/tests/unit/stats/services/DateUtils.js @@ -21,6 +21,9 @@ describe("FM.stats.DateUtils", function() { beforeEach(inject(function ( $rootScope, $injector, $controller ) { $scope = $rootScope.$new(); + var today = new Date("2015-07-01"); + jasmine.clock().mockDate(today); + DateUtils = $injector.get("DateUtils"); })); @@ -35,4 +38,26 @@ describe("FM.stats.DateUtils", function() { }); + describe("historicDatePeriods", function(){ + + it("should return historic date periods", function(){ + var dates = DateUtils.historicDatePeriods("2015-07-20", "2015-07-27", 3); + expect(dates.length).toEqual(3); + expect(dates[0].from).toEqual("2015-07-13"); + expect(dates[1].from).toEqual("2015-07-06"); + expect(dates[2].from).toEqual("2015-06-29"); + expect(dates[0].to).toEqual("2015-07-19"); + expect(dates[1].to).toEqual("2015-07-12"); + expect(dates[2].to).toEqual("2015-07-05"); + }); + + it("should default end to today", function(){ + var dates = DateUtils.historicDatePeriods("2015-06-29", undefined, 1); + expect(dates.length).toEqual(1); + expect(dates[0].from).toEqual("2015-07-27"); + expect(dates[0].to).toEqual("2015-07-28"); + }); + + }); + }); From 7f1fe3e8b209d0723d1f468bb763e35841912f96 Mon Sep 17 00:00:00 2001 From: James Warren Date: Mon, 27 Jul 2015 17:06:02 +0100 Subject: [PATCH 3/5] test UserStatsCtrl --- app/index.html | 3 + app/js/users/controllers/UserStatsCtrl.js | 12 +- tests/unit/users/controllers/UserStatsCtrl.js | 157 ++++++++++++++++++ 3 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 tests/unit/users/controllers/UserStatsCtrl.js diff --git a/app/index.html b/app/index.html index 5d860e22..1e538c67 100644 --- a/app/index.html +++ b/app/index.html @@ -141,6 +141,9 @@ + + + diff --git a/app/js/users/controllers/UserStatsCtrl.js b/app/js/users/controllers/UserStatsCtrl.js index 021e4373..641050f5 100644 --- a/app/js/users/controllers/UserStatsCtrl.js +++ b/app/js/users/controllers/UserStatsCtrl.js @@ -6,16 +6,10 @@ angular.module("FM.users.UserStatsCtrl", [ "FM.api.UsersResource", "FM.stats", - "ngMockE2E" - + "ngRoute", + "chart.js", + "ui.bootstrap.datepicker" ]) -.run(["$httpBackend", function ($httpBackend) { - var stats = {"most_played_tracks": [{"track": {"album": {"id": "0fad2b5a-e947-4d2a-81e5-f1df52389895", "spotify_uri": "spotify:album:0BFzNaeaNv4mahOzwZFGHK", "name": "Royal Blood"}, "name": "Figure It Out", "spotify_uri": "spotify:track:3MjrueDQKVr6xDDseZwhEd", "artists": [], "duration": 184053, "id": "32edd7b4-7f5d-42e3-8a0e-0b54c9f02d15"}, "total": 6}, {"track": {"album": {"id": "a1da5909-3431-4154-b412-27bee155fb59", "spotify_uri": "spotify:album:6Clg4KBsvQUwCxf9dADoIt", "name": "Crying Lightning"}, "name": "Red Right Hand", "spotify_uri": "spotify:track:4eMHHSB98QBxOECsXInbxv", "artists": [], "duration": 259813, "id": "6bd3aa37-9916-43d4-a66a-29c762f4052f"}, "total": 4}, {"track": {"album": {"id": "78cad758-bd0b-4d8b-8dd5-5ca8a5bc76ae", "spotify_uri": "spotify:album:1XOSDyhzUmOFrp3ChmYFKO", "name": "Ship To Wreck"}, "name": "Ship To Wreck", "spotify_uri": "spotify:track:6WFpbFOV9q3Aa1I9tegWNN", "artists": [], "duration": 234526, "id": "fec6875e-a58d-4616-bdb6-4984a93a404d"}, "total": 3}, {"track": {"album": {"id": "26a21322-8495-4444-94f0-f016cf2daf24", "spotify_uri": "spotify:album:4AZpJ7WG1RFcimSggc05ZC", "name": "The Warning"}, "name": "Over And Over", "spotify_uri": "spotify:track:6m5D7zGVbzAxceDXQTsRSX", "artists": [], "duration": 347880, "id": "3b227506-cdac-4495-9799-cc5bd85697b5"}, "total": 3}, {"track": {"album": {"id": "3d78823d-b4d4-4a44-8a08-dec210d8a229", "spotify_uri": "spotify:album:26Bm3PBTkGz1eIMzXsfc6g", "name": "Ritual"}, "name": "Turn The Bells", "spotify_uri": "spotify:track:1ZMPQa4U9Sx7HZna41kvpS", "artists": [], "duration": 304093, "id": "5a0b7624-43ff-4761-b30f-792ff8101e6e"}, "total": 3}, {"track": {"album": {"id": "1d3f6c97-2a68-4ddb-9959-fd2463e85543", "spotify_uri": "spotify:album:2wart5Qjnvx1fd7LPdQxgJ", "name": "Drones"}, "name": "The Globalist - Premium Only", "spotify_uri": "spotify:track:6BGxbBw5J314z6BDxbEanm", "artists": [], "duration": 607282, "id": "4ee0bbe4-4895-44d3-8025-eeb5d89596e9"}, "total": 3}, {"track": {"album": {"id": "71b5c930-1936-47e3-b13e-8273ebe4200d", "spotify_uri": "spotify:album:7x7oLEHfjiYLzLHS93G1lr", "name": "Little Black Submarines"}, "name": "Little Black Submarines - radio edit", "spotify_uri": "spotify:track:17609ifVvJ7Npd8IqVnRFc", "artists": [], "duration": 204692, "id": "9143e2e6-7695-4918-98d4-9edfbd78d2ac"}, "total": 3}, {"track": {"album": {"id": "132e8bfb-7f1c-4457-98ca-41c3867ad98d", "spotify_uri": "spotify:album:76FdMKQqoDqPf95j5vq1AJ", "name": "Why Make Sense?"}, "name": "Huarache Lights", "spotify_uri": "spotify:track:6awtKwZBUZQzBFuqxjLsjO", "artists": [], "duration": 329169, "id": "68bc5bf0-d299-41d5-be66-94be78aab599"}, "total": 2}, {"track": {"album": {"id": "562b4369-9127-4223-af2a-3021981bf5f1", "spotify_uri": "spotify:album:25irJgxRNTlyg8pUmWfDVG", "name": "Greatest Hits"}, "name": "Homeward Bound", "spotify_uri": "spotify:track:1WCx3vqkBSPhwDz584C9tk", "artists": [], "duration": 162173, "id": "df8bdcf1-008d-48b6-b306-41ad25336368"}, "total": 2}, {"track": {"album": {"id": "3d78823d-b4d4-4a44-8a08-dec210d8a229", "spotify_uri": "spotify:album:26Bm3PBTkGz1eIMzXsfc6g", "name": "Ritual"}, "name": "Bad Love", "spotify_uri": "spotify:track:6IyNytssOakxZyyhef8Rmj", "artists": [], "duration": 237920, "id": "b1bd98a0-323b-43cd-a69e-587c09d0f3ff"}, "total": 2}], "total_plays": 215, "total_play_time": 57697107, "most_played_genres": [{"total": 63, "name": "rock"}, {"total": 55, "name": "indie rock"}, {"total": 53, "name": "permanent wave"}, {"total": 38, "name": "indietronica"}, {"total": 33, "name": "folk-pop"}, {"total": 31, "name": "new rave"}, {"total": 29, "name": "indie folk"}, {"total": 26, "name": "chamber pop"}, {"total": 25, "name": "piano rock"}, {"total": 25, "name": "indie pop"}], "most_played_artists": [{"total": 24, "artist": {"id": "ec32ec9e-6c15-4a6b-8a66-a1f4a86ed31c", "uri": "spotify:artist:12Chz98pHFMPJEknJQMWvI", "name": "Muse"}}, {"total": 9, "artist": {"id": "d01f6913-264f-40b6-9018-7a26c7fc7537", "uri": "spotify:artist:023YMawCG3OvACmRjWxLWC", "name": "The Cat Empire"}}, {"total": 9, "artist": {"id": "d2a9b543-7fa0-4438-b44a-1c32114dbceb", "uri": "spotify:artist:6ssXMmc5EOUrauZxirM910", "name": "White Lies"}}, {"total": 8, "artist": {"id": "ccf27755-ca07-4421-bc9f-5a7fa00b8624", "uri": "spotify:artist:6fBF4MULW5yMzyGaon1kUt", "name": "John Butler Trio"}}, {"total": 8, "artist": {"id": "8b292f2f-95cd-4a5c-9fa4-295ea5ab012d", "uri": "spotify:artist:7sjttK1WcZeyLPn3IsQ62L", "name": "Noel Gallagher's High Flying Birds"}}, {"total": 8, "artist": {"id": "d8ac4824-32b6-48c7-8ab5-1a0540d8ff51", "uri": "spotify:artist:3pTE9iaJTkWns3mxpNQlJV", "name": "Bombay Bicycle Club"}}, {"total": 7, "artist": {"id": "cb141ddf-4764-40c8-a368-1f0246b883fe", "uri": "spotify:artist:7Ln80lUS6He07XvHI8qqHH", "name": "Arctic Monkeys"}}, {"total": 7, "artist": {"id": "fa5bacd8-8631-4e40-83dc-32eb94a047ff", "uri": "spotify:artist:37uLId6Z5ZXCx19vuruvv5", "name": "Hot Chip"}}, {"total": 7, "artist": {"id": "fcb3373b-b5bc-4305-aa2d-b4ff60791fc6", "uri": "spotify:artist:5schNIzWdI9gJ1QRK8SBnc", "name": "Ben Howard"}}, {"total": 7, "artist": {"id": "4b4a124d-fd96-45b7-9fb5-e174e2369b26", "uri": "spotify:artist:7mnBLXK823vNxN3UWB7Gfz", "name": "The Black Keys"}}]}; - - $httpBackend.whenGET(/.*users\/.*\/stats.*/).respond(200, stats); - $httpBackend.whenGET(/.*users\/.*/).respond(200, { "avatar_url": "https://lh6.googleusercontent.com/-WOwGfU-QYjE/AAAAAAAAAAI/AAAAAAAAABE/lqC4XiCND18/photo.jpg", "display_name": "James Warren", "family_name": "Warren", "given_name": "James", "id": "785bc064-0e08-4ea3-98d5-446e497bd213", "spotify_playlists": null }); - $httpBackend.whenGET(/.*/).passThrough(); -}]) /** * @method config * @param {Provider} $routeProvider diff --git a/tests/unit/users/controllers/UserStatsCtrl.js b/tests/unit/users/controllers/UserStatsCtrl.js new file mode 100644 index 00000000..2b580b56 --- /dev/null +++ b/tests/unit/users/controllers/UserStatsCtrl.js @@ -0,0 +1,157 @@ +"use strict"; + +describe("FM.users.UserStatsCtrl", function() { + + var $rootScope, $location, $route, $scope, $filter, $q, $httpBackend, + CHART_COLOURS, CHART_OPTIONS, UsersResource, stats, user; + + beforeEach(function (){ + module("FM.users.UserStatsCtrl"); + }); + + beforeEach(inject(function (_$httpBackend_) { + $httpBackend = _$httpBackend_; + + stats = {"most_played_tracks": [{"track": {"album": {"id": "0fad2b5a-e947-4d2a-81e5-f1df52389895", "spotify_uri": "spotify:album:0BFzNaeaNv4mahOzwZFGHK", "name": "Royal Blood"}, "name": "Figure It Out", "spotify_uri": "spotify:track:3MjrueDQKVr6xDDseZwhEd", "artists": [], "duration": 184053, "id": "32edd7b4-7f5d-42e3-8a0e-0b54c9f02d15"}, "total": 6}, {"track": {"album": {"id": "a1da5909-3431-4154-b412-27bee155fb59", "spotify_uri": "spotify:album:6Clg4KBsvQUwCxf9dADoIt", "name": "Crying Lightning"}, "name": "Red Right Hand", "spotify_uri": "spotify:track:4eMHHSB98QBxOECsXInbxv", "artists": [], "duration": 259813, "id": "6bd3aa37-9916-43d4-a66a-29c762f4052f"}, "total": 4}, {"track": {"album": {"id": "78cad758-bd0b-4d8b-8dd5-5ca8a5bc76ae", "spotify_uri": "spotify:album:1XOSDyhzUmOFrp3ChmYFKO", "name": "Ship To Wreck"}, "name": "Ship To Wreck", "spotify_uri": "spotify:track:6WFpbFOV9q3Aa1I9tegWNN", "artists": [], "duration": 234526, "id": "fec6875e-a58d-4616-bdb6-4984a93a404d"}, "total": 3}, {"track": {"album": {"id": "26a21322-8495-4444-94f0-f016cf2daf24", "spotify_uri": "spotify:album:4AZpJ7WG1RFcimSggc05ZC", "name": "The Warning"}, "name": "Over And Over", "spotify_uri": "spotify:track:6m5D7zGVbzAxceDXQTsRSX", "artists": [], "duration": 347880, "id": "3b227506-cdac-4495-9799-cc5bd85697b5"}, "total": 3}, {"track": {"album": {"id": "3d78823d-b4d4-4a44-8a08-dec210d8a229", "spotify_uri": "spotify:album:26Bm3PBTkGz1eIMzXsfc6g", "name": "Ritual"}, "name": "Turn The Bells", "spotify_uri": "spotify:track:1ZMPQa4U9Sx7HZna41kvpS", "artists": [], "duration": 304093, "id": "5a0b7624-43ff-4761-b30f-792ff8101e6e"}, "total": 3}, {"track": {"album": {"id": "1d3f6c97-2a68-4ddb-9959-fd2463e85543", "spotify_uri": "spotify:album:2wart5Qjnvx1fd7LPdQxgJ", "name": "Drones"}, "name": "The Globalist - Premium Only", "spotify_uri": "spotify:track:6BGxbBw5J314z6BDxbEanm", "artists": [], "duration": 607282, "id": "4ee0bbe4-4895-44d3-8025-eeb5d89596e9"}, "total": 3}, {"track": {"album": {"id": "71b5c930-1936-47e3-b13e-8273ebe4200d", "spotify_uri": "spotify:album:7x7oLEHfjiYLzLHS93G1lr", "name": "Little Black Submarines"}, "name": "Little Black Submarines - radio edit", "spotify_uri": "spotify:track:17609ifVvJ7Npd8IqVnRFc", "artists": [], "duration": 204692, "id": "9143e2e6-7695-4918-98d4-9edfbd78d2ac"}, "total": 3}, {"track": {"album": {"id": "132e8bfb-7f1c-4457-98ca-41c3867ad98d", "spotify_uri": "spotify:album:76FdMKQqoDqPf95j5vq1AJ", "name": "Why Make Sense?"}, "name": "Huarache Lights", "spotify_uri": "spotify:track:6awtKwZBUZQzBFuqxjLsjO", "artists": [], "duration": 329169, "id": "68bc5bf0-d299-41d5-be66-94be78aab599"}, "total": 2}, {"track": {"album": {"id": "562b4369-9127-4223-af2a-3021981bf5f1", "spotify_uri": "spotify:album:25irJgxRNTlyg8pUmWfDVG", "name": "Greatest Hits"}, "name": "Homeward Bound", "spotify_uri": "spotify:track:1WCx3vqkBSPhwDz584C9tk", "artists": [], "duration": 162173, "id": "df8bdcf1-008d-48b6-b306-41ad25336368"}, "total": 2}, {"track": {"album": {"id": "3d78823d-b4d4-4a44-8a08-dec210d8a229", "spotify_uri": "spotify:album:26Bm3PBTkGz1eIMzXsfc6g", "name": "Ritual"}, "name": "Bad Love", "spotify_uri": "spotify:track:6IyNytssOakxZyyhef8Rmj", "artists": [], "duration": 237920, "id": "b1bd98a0-323b-43cd-a69e-587c09d0f3ff"}, "total": 2}], "total_plays": 215, "total_play_time": 57697107, "most_played_genres": [{"total": 63, "name": "rock"}, {"total": 55, "name": "indie rock"}, {"total": 53, "name": "permanent wave"}, {"total": 38, "name": "indietronica"}, {"total": 33, "name": "folk-pop"}, {"total": 31, "name": "new rave"}, {"total": 29, "name": "indie folk"}, {"total": 26, "name": "chamber pop"}, {"total": 25, "name": "piano rock"}, {"total": 25, "name": "indie pop"}], "most_played_artists": [{"total": 24, "artist": {"id": "ec32ec9e-6c15-4a6b-8a66-a1f4a86ed31c", "uri": "spotify:artist:12Chz98pHFMPJEknJQMWvI", "name": "Muse"}}, {"total": 9, "artist": {"id": "d01f6913-264f-40b6-9018-7a26c7fc7537", "uri": "spotify:artist:023YMawCG3OvACmRjWxLWC", "name": "The Cat Empire"}}, {"total": 9, "artist": {"id": "d2a9b543-7fa0-4438-b44a-1c32114dbceb", "uri": "spotify:artist:6ssXMmc5EOUrauZxirM910", "name": "White Lies"}}, {"total": 8, "artist": {"id": "ccf27755-ca07-4421-bc9f-5a7fa00b8624", "uri": "spotify:artist:6fBF4MULW5yMzyGaon1kUt", "name": "John Butler Trio"}}, {"total": 8, "artist": {"id": "8b292f2f-95cd-4a5c-9fa4-295ea5ab012d", "uri": "spotify:artist:7sjttK1WcZeyLPn3IsQ62L", "name": "Noel Gallagher's High Flying Birds"}}, {"total": 8, "artist": {"id": "d8ac4824-32b6-48c7-8ab5-1a0540d8ff51", "uri": "spotify:artist:3pTE9iaJTkWns3mxpNQlJV", "name": "Bombay Bicycle Club"}}, {"total": 7, "artist": {"id": "cb141ddf-4764-40c8-a368-1f0246b883fe", "uri": "spotify:artist:7Ln80lUS6He07XvHI8qqHH", "name": "Arctic Monkeys"}}, {"total": 7, "artist": {"id": "fa5bacd8-8631-4e40-83dc-32eb94a047ff", "uri": "spotify:artist:37uLId6Z5ZXCx19vuruvv5", "name": "Hot Chip"}}, {"total": 7, "artist": {"id": "fcb3373b-b5bc-4305-aa2d-b4ff60791fc6", "uri": "spotify:artist:5schNIzWdI9gJ1QRK8SBnc", "name": "Ben Howard"}}, {"total": 7, "artist": {"id": "4b4a124d-fd96-45b7-9fb5-e174e2369b26", "uri": "spotify:artist:7mnBLXK823vNxN3UWB7Gfz", "name": "The Black Keys"}}]}; // jshint ignore:line + user = { "avatar_url": "https://lh6.googleusercontent.com/-WOwGfU-QYjE/AAAAAAAAAAI/AAAAAAAAABE/lqC4XiCND18/photo.jpg", "display_name": "James Warren", "family_name": "Warren", "given_name": "James", "id": "785bc064-0e08-4ea3-98d5-446e497bd213", "spotify_playlists": null }; + + $httpBackend.whenGET(/.*users\/.*\/stats.*/).respond(200, stats); + $httpBackend.whenGET(/.*users\/.*/).respond(200, user); + $httpBackend.whenGET(/partials\/.*/).respond(200); + })); + + + beforeEach(inject(function ( _$rootScope_, $injector, $controller ) { + $rootScope = _$rootScope_; + $scope = $rootScope.$new(); + $q = $injector.get("$q"); + + $filter = $injector.get("$filter"); + $route = $injector.get("$route"); + + $location = $injector.get("$location"); + $location.search = function () { + return { + from: "2015-01-14", + to: "2015-01-15" + } + }; + spyOn($location, "search").and.callThrough(); + + UsersResource = $injector.get("UsersResource"); + spyOn(UsersResource, "stats").and.callThrough(); + + CHART_COLOURS = []; + CHART_OPTIONS = {}; + + var today = new Date("2015-07-01"); + jasmine.clock().mockDate(today); + + $controller("UserStatsCtrl", { + $scope: $scope, + $q: $q, + $filter: $filter, + $location: $location, + CHART_OPTIONS: CHART_OPTIONS, + CHART_COLOURS: CHART_COLOURS, + UsersResource: UsersResource, + stats: stats, + user: user + }); + })); + + afterEach(function() { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + it("should load views", function() { + $location.path("/users/2448a459-1bcc-4855-9a94-504004364242"); + $rootScope.$digest(); + $httpBackend.flush(); + expect($route.current.controller).toBe("UserStatsCtrl"); + }); + + it("should attach data to $scope", function(){ + $httpBackend.flush(); + expect($scope.stats).toEqual(stats); + expect($scope.chartColours).toEqual(CHART_COLOURS); + }); + + it("should open datepicker", function(){ + $httpBackend.flush(); + var event = { + preventDefault: jasmine.createSpy(), + stopPropagation: jasmine.createSpy() + }; + + $scope.openDatepicker(event, "test"); + expect($scope.datepickerOpened.test).toBe(true); + expect(event.preventDefault).toHaveBeenCalled(); + expect(event.stopPropagation).toHaveBeenCalled(); + + $scope.openDatepicker(event, "test"); + expect($scope.datepickerOpened.test).toBe(false); + }); + + describe("filter", function () { + + it("should filter from JS dates", function(){ + $scope.filter = { + from: new Date("2015-07-01"), + to: new Date("2015-07-02") + }; + $httpBackend.flush(); + $scope.updateFilter(); + expect($location.search).toHaveBeenCalledWith({ + from: "2015-07-01", + to: "2015-07-02" + }); + }); + + it("should filter from date strings", function(){ + $scope.filter = { from: "2015-07-01", to: "2015-07-02" }; + $httpBackend.flush(); + $scope.updateFilter(); + expect($location.search).toHaveBeenCalledWith({ + from: "2015-07-01", + to: "2015-07-02" + }); + }); + + it("should clear filters", function(){ + $scope.filter = { from: undefined, to: undefined }; + $httpBackend.flush(); + $scope.updateFilter(); + expect($location.search).toHaveBeenCalledWith({ from: undefined, to: undefined, all: true }); + }); + + }); + + describe("init", function () { + + it("should add playTime data", function(){ + $httpBackend.flush(); + expect($scope.playTime.data).toEqual([[ 962, 962, 962, 962 ]]); + expect($scope.playTime.labels).toEqual(["11-07-2015", "12-07-2015", "13-07-2015", "14-01-2015"]); + }); + + it("should load historic data based on start/end dates", function(){ + $httpBackend.flush(); + $scope.playTime.data = [[]]; + $scope.playTime.labels = []; + + UsersResource.stats.calls.reset(); + $scope.loadHistoricData("2015-07-14","2015-07-21"); + $httpBackend.flush(); + + expect(UsersResource.stats).toHaveBeenCalledWith({ from: "2015-07-07", to: "2015-07-13", id: "785bc064-0e08-4ea3-98d5-446e497bd213" }); + expect(UsersResource.stats).toHaveBeenCalledWith({ from: "2015-06-30", to: "2015-07-06", id: "785bc064-0e08-4ea3-98d5-446e497bd213" }); + expect(UsersResource.stats).toHaveBeenCalledWith({ from: "2015-06-23", to: "2015-06-29", id: "785bc064-0e08-4ea3-98d5-446e497bd213" }); + expect($scope.playTime.data).toEqual([[ 962, 962, 962 ]]); + expect($scope.playTime.labels).toEqual(["23-06-2015", "30-06-2015", "07-07-2015"]); + }); + + }); + +}); From b9b3dcc8879a9db7c4f66d2a27346161a4307dfc Mon Sep 17 00:00:00 2001 From: James Warren Date: Mon, 27 Jul 2015 17:07:30 +0100 Subject: [PATCH 4/5] update stats layout to reflect changes made in user stats --- app/partials/stats.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/partials/stats.html b/app/partials/stats.html index 401d8f95..88fbd75d 100644 --- a/app/partials/stats.html +++ b/app/partials/stats.html @@ -12,6 +12,8 @@

FM Stats

+ +
@@ -40,7 +42,7 @@

{{ stats.total_play_time | time }}

- +

Most Active DJ

{{ activeDj.labels[0] }}

@@ -48,11 +50,11 @@

Most Active DJ

- +

Play time

{{ playTime.series[0] }} {{ playTime.data[0][0]/60 }} hours{{ playTime.data[0][0] }} minutes

-

Select from date to view historic play time stats

+

Set filter dates to view historic play time from previous periods

From 06b11ff8b22a6af4d708b6ec91d2d4a816bfc246 Mon Sep 17 00:00:00 2001 From: James Warren Date: Mon, 27 Jul 2015 17:17:43 +0100 Subject: [PATCH 5/5] add users link to track --- app/partials/track.html | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/partials/track.html b/app/partials/track.html index 2922fa3e..9c28523e 100644 --- a/app/partials/track.html +++ b/app/partials/track.html @@ -1,11 +1,13 @@
Selected by: - {{ user.display_name }} + + {{ user.display_name }} +