{{member.name}}
-{{member.email}}
-diff --git a/ghost/admin/app/components/gh-members-list-item.js b/ghost/admin/app/components/gh-members-list-item.js new file mode 100644 index 0000000000..0209d010dd --- /dev/null +++ b/ghost/admin/app/components/gh-members-list-item.js @@ -0,0 +1,25 @@ +import Component from '@ember/component'; +import moment from 'moment'; +import {alias} from '@ember/object/computed'; +import {computed} from '@ember/object'; +import {inject as service} from '@ember/service'; + +export default Component.extend({ + ghostPaths: service(), + notifications: service(), + router: service(), + + tagName: 'li', + classNames: ['gh-list-row', 'gh-tags-list-item'], + + active: false, + + id: alias('member.id'), + email: alias('member.email'), + name: computed('member.name', function () { + return this.member.name || '-'; + }), + subscribedAt: computed('member.createdAt', function () { + return moment(this.member.createdAt).format('YYYY-MM-DD HH:mm'); + }) +}); diff --git a/ghost/admin/app/controllers/members.js b/ghost/admin/app/controllers/members.js index 02d74cf0ae..d10b80570b 100644 --- a/ghost/admin/app/controllers/members.js +++ b/ghost/admin/app/controllers/members.js @@ -11,7 +11,6 @@ export default Controller.extend({ meta: null, members: null, searchText: '', - init() { this._super(...arguments); this.set('members', this.store.peekAll('member')); @@ -27,13 +26,69 @@ export default Controller.extend({ } let {name, email} = member; - return name.toLowerCase().indexOf(searchText) >= 0 - || email.toLowerCase().indexOf(searchText) >= 0; + return (name && name.toLowerCase().indexOf(searchText) >= 0) + || (email && email.toLowerCase().indexOf(searchText) >= 0); }); return filtered; }), + chartData: computed('members.@each', function () { + let {members} = this; + let dateFormat = 'DD-MM-YYYY'; + let monthData = []; + let dateLabel = []; + let startDate = moment().subtract(29, 'days'); + for (let i = 0; i < 30; i++) { + let m = moment(startDate).add(i, 'days'); + dateLabel.push(m.format(dateFormat)); + let membersTillDate = members.filter((member) => { + let isValid = moment(member.createdAt).isSameOrBefore(m, 'day'); + return isValid; + }).length; + monthData.push(membersTillDate); + } + return { + data: { + labels: dateLabel, + datasets: [ + { + label: 'Total Members', + data: monthData, + fill: false, + strokeColor: 'rgba(151,187,205,1)', + pointColor: 'rgba(151,187,205,1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(151,187,205,1)' + } + ] + }, + options: { + responsive: true, + maintainAspectRatio: false, + title: { + display: true, + text: 'Total members in last 30 days' + }, + scales: { + xAxes: [{ + type: 'time', + time: { + format: dateFormat, + tooltipFormat: 'll' + }, + scaleLabel: { + display: true, + labelString: 'Date' + }, + display: true + }] + } + } + }; + }), + fetchMembers: task(function* () { let newFetchDate = new Date(); let results; diff --git a/ghost/admin/app/templates/components/gh-members-list-item.hbs b/ghost/admin/app/templates/components/gh-members-list-item.hbs new file mode 100644 index 0000000000..02cbf26df0 --- /dev/null +++ b/ghost/admin/app/templates/components/gh-members-list-item.hbs @@ -0,0 +1,19 @@ +{{#link-to "member" member class="gh-list-data" title="Edit Member"}} +
{{member.email}}
-No members found.
- {{/if}} - {{/if}} + + {{/if}} + {{/if}} + + \ No newline at end of file diff --git a/ghost/admin/package.json b/ghost/admin/package.json index a884ee962f..a2d507e980 100644 --- a/ghost/admin/package.json +++ b/ghost/admin/package.json @@ -54,6 +54,7 @@ "ember-cli-app-version": "3.2.0", "ember-cli-babel": "7.12.0", "ember-cli-chai": "0.5.0", + "ember-cli-chart": "^3.5.0", "ember-cli-dependency-checker": "3.2.0", "ember-cli-deprecation-workflow": "1.0.1", "ember-cli-eslint": "5.1.0", diff --git a/ghost/admin/yarn.lock b/ghost/admin/yarn.lock index 86c9d3e6ef..75e358bbe4 100644 --- a/ghost/admin/yarn.lock +++ b/ghost/admin/yarn.lock @@ -3393,6 +3393,29 @@ charm@^1.0.0: dependencies: inherits "^2.0.1" +chart.js@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.8.0.tgz#b703b10d0f4ec5079eaefdcd6ca32dc8f826e0e9" + integrity sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w== + dependencies: + chartjs-color "^2.1.0" + moment "^2.10.2" + +chartjs-color-string@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71" + integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A== + dependencies: + color-name "^1.0.0" + +chartjs-color@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.3.0.tgz#0e7e1e8dba37eae8415fd3db38bf572007dd958f" + integrity sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g== + dependencies: + chartjs-color-string "^0.6.0" + color-convert "^0.5.3" + check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" @@ -3589,6 +3612,11 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" +color-convert@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd" + integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0= + color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -4678,6 +4706,16 @@ ember-cli-chai@0.5.0: rollup-plugin-commonjs "^8.0.2" rollup-plugin-node-resolve "^3.0.0" +ember-cli-chart@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/ember-cli-chart/-/ember-cli-chart-3.5.0.tgz#c20df59413cd3473d17a39b40db810ebb2b45544" + integrity sha512-L7HWIOGXKEV/UKR9cioKQXlsDmx2DPAScirx6tQXB5aBx5hOYGSx6QHG2dSzMimI86hD5JstbuqeTyTfmRv+RA== + dependencies: + chart.js "^2.8.0" + ember-cli-babel "^7.7.3" + ember-cli-node-assets "^0.2.2" + fastboot-transform "^0.1.2" + ember-cli-dependency-checker@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.2.0.tgz#9202ad9e14d6fda33cffc22a11c343c2a8885330" @@ -4844,7 +4882,7 @@ ember-cli-moment-shim@3.7.1, ember-cli-moment-shim@^3.7.1: moment "^2.19.3" moment-timezone "^0.5.13" -ember-cli-node-assets@0.2.2: +ember-cli-node-assets@0.2.2, ember-cli-node-assets@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/ember-cli-node-assets/-/ember-cli-node-assets-0.2.2.tgz#d2d55626e7cc6619f882d7fe55751f9266022708" integrity sha1-0tVWJufMZhn4gtf+VXUfkmYCJwg= @@ -6206,7 +6244,7 @@ fast-sourcemap-concat@^1.4.0: source-map-url "^0.3.0" sourcemap-validator "^1.1.0" -fastboot-transform@^0.1.3: +fastboot-transform@^0.1.2, fastboot-transform@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/fastboot-transform/-/fastboot-transform-0.1.3.tgz#7dea0b117594afd8772baa6c9b0919644e7f7dcd" integrity sha512-6otygPIJw1ARp1jJb+6KVO56iKBjhO+5x59RSC9qiZTbZRrv+HZAuP00KD3s+nWMvcFDemtdkugki9DNFTTwCQ== @@ -8895,7 +8933,7 @@ moment-timezone@^0.5.13: dependencies: moment ">= 2.9.0" -"moment@>= 2.9.0", moment@^2.19.3: +"moment@>= 2.9.0", moment@^2.10.2, moment@^2.19.3: version "2.24.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==