diff --git a/ghost/admin/app/services/dashboard-stats.js b/ghost/admin/app/services/dashboard-stats.js index e23b17b51a..0fc19af58b 100644 --- a/ghost/admin/app/services/dashboard-stats.js +++ b/ghost/admin/app/services/dashboard-stats.js @@ -3,6 +3,8 @@ import moment from 'moment-timezone'; import {task} from 'ember-concurrency'; import {tracked} from '@glimmer/tracking'; +import mergeStatsByDate from 'ghost-admin/utils/merge-stats-by-date'; + /** * @typedef MrrStat * @type {Object} @@ -461,39 +463,7 @@ export default class DashboardStatsService extends Service { } } - function mergeDates(list, entry) { - const [current, ...rest] = list; - - if (!current) { - return entry ? [entry] : []; - } - - if (!entry) { - return mergeDates(rest, { - date: current.date, - count: current.count, - positiveDelta: current.positive_delta, - negativeDelta: current.negative_delta, - signups: current.signups, - cancellations: current.cancellations - }); - } - - if (current.date === entry.date) { - return mergeDates(rest, { - date: entry.date, - count: entry.count + current.count, - positiveDelta: entry.positiveDelta + current.positive_delta, - negativeDelta: entry.negativeDelta + current.negative_delta, - signups: entry.signups + current.signups, - cancellations: entry.cancellations + current.cancellations - }); - } - - return [entry].concat(mergeDates(list)); - } - - const subscriptionCountStats = mergeDates(result.stats); + const subscriptionCountStats = mergeStatsByDate(result.stats); this.paidMembersByCadence = paidMembersByCadence; this.paidMembersByTier = paidMembersByTier; @@ -524,7 +494,7 @@ export default class DashboardStatsService extends Service { this.memberCountStats = this.dashboardMocks.memberCountStats; return; } - + const stats = yield this.membersStats.fetchMemberCount(); this.memberCountStats = stats.stats.map((d) => { return { diff --git a/ghost/admin/app/utils/merge-stats-by-date.js b/ghost/admin/app/utils/merge-stats-by-date.js new file mode 100644 index 0000000000..797c4f0d9e --- /dev/null +++ b/ghost/admin/app/utils/merge-stats-by-date.js @@ -0,0 +1,31 @@ +export default function mergeDates(list, entry) { + const [current, ...rest] = list; + + if (!current) { + return entry ? [entry] : []; + } + + if (!entry) { + return mergeDates(rest, { + date: current.date, + count: current.count, + positiveDelta: current.positive_delta, + negativeDelta: current.negative_delta, + signups: current.signups, + cancellations: current.cancellations + }); + } + + if (current.date === entry.date) { + return mergeDates(rest, { + date: entry.date, + count: entry.count + current.count, + positiveDelta: entry.positiveDelta + current.positive_delta, + negativeDelta: entry.negativeDelta + current.negative_delta, + signups: entry.signups + current.signups, + cancellations: entry.cancellations + current.cancellations + }); + } + + return [entry].concat(mergeDates(list)); +} diff --git a/ghost/admin/tests/unit/utils/merge-stats-by-date-test.js b/ghost/admin/tests/unit/utils/merge-stats-by-date-test.js new file mode 100644 index 0000000000..62480d478a --- /dev/null +++ b/ghost/admin/tests/unit/utils/merge-stats-by-date-test.js @@ -0,0 +1,184 @@ +import mergeStatsByDate from 'ghost-admin/utils/merge-stats-by-date'; +import {describe, it} from 'mocha'; +import {expect} from 'chai'; + +const STATS_DATA = [ + { + date: '2024-06-22', + tier: '111111111111111111111111', + cadence: 'month', + positive_delta: 0, + negative_delta: 0, + signups: 0, + cancellations: 0, + count: 456 + }, + { + date: '2024-06-22', + tier: '111111111111111111111111', + cadence: 'year', + positive_delta: 1, + negative_delta: 1, + signups: 0, + cancellations: 0, + count: 1354 + }, + { + date: '2024-06-23', + tier: '111111111111111111111111', + cadence: 'month', + positive_delta: 0, + negative_delta: 0, + signups: 0, + cancellations: 0, + count: 456 + }, + { + date: '2024-06-23', + tier: '111111111111111111111111', + cadence: 'year', + positive_delta: 1, + negative_delta: 1, + signups: 0, + cancellations: 0, + count: 1354 + }, + { + date: '2024-06-23', + tier: '111111111111111111111113', + cadence: 'year', + positive_delta: 0, + negative_delta: 0, + signups: 0, + cancellations: 0, + count: 400 + }, + { + date: '2024-06-24', + tier: '111111111111111111111111', + cadence: 'year', + positive_delta: 3, + negative_delta: 2, + signups: 1, + cancellations: 0, + count: 1355 + }, + { + date: '2024-06-24', + tier: '111111111111111111111113', + cadence: 'year', + positive_delta: 2, + negative_delta: 1, + signups: 2, + cancellations: 1, + count: 401 + }, + { + date: '2024-06-24', + tier: '111111111111111111111112', + cadence: 'year', + positive_delta: 1, + negative_delta: 0, + signups: 1, + cancellations: 0, + count: 55 + }, + { + date: '2024-06-25', + tier: '111111111111111111111111', + cadence: 'month', + positive_delta: 0, + negative_delta: 1, + signups: 0, + cancellations: 1, + count: 455 + }, + { + date: '2024-06-25', + tier: '111111111111111111111111', + cadence: 'year', + positive_delta: 2, + negative_delta: 5, + signups: 1, + cancellations: 4, + count: 1352 + }, + { + date: '2024-06-25', + tier: '111111111111111111111113', + cadence: 'year', + positive_delta: 1, + negative_delta: 2, + signups: 1, + cancellations: 2, + count: 400 + }, + { + date: '2024-06-26', + tier: '111111111111111111111111', + cadence: 'year', + positive_delta: 2, + negative_delta: 2, + signups: 0, + cancellations: 0, + count: 1352 + }, + { + date: '2024-06-26', + tier: '111111111111111111111113', + cadence: 'year', + positive_delta: 0, + negative_delta: 0, + signups: 0, + cancellations: 0, + count: 400 + } +]; + +describe('mergeStatsByDate', function () { + it('merges stats as expected', function () { + const result = mergeStatsByDate(STATS_DATA); + expect(result).to.deep.equal([ + { + date: '2024-06-22', + count: 1810, + positiveDelta: 1, + negativeDelta: 1, + signups: 0, + cancellations: 0 + }, + { + date: '2024-06-23', + count: 2210, + positiveDelta: 1, + negativeDelta: 1, + signups: 0, + cancellations: 0 + }, + { + date: '2024-06-24', + count: 1811, + positiveDelta: 6, + negativeDelta: 3, + signups: 4, + cancellations: 1 + }, + { + date: '2024-06-25', + count: 2207, + positiveDelta: 3, + negativeDelta: 8, + signups: 2, + cancellations: 7 + }, + { + date: '2024-06-26', + count: 1752, + positiveDelta: 2, + negativeDelta: 2, + signups: 0, + cancellations: 0 + } + ]); + }); +});