Updated mock data format for source attribution

refs https://github.com/TryGhost/Team/issues/1891

- cleans up mock stats data from hardcoded values for each period to instead have the global stats format with date
- the value for each period is calculated dynamically based on selected option
- is in line with how API data is expected to be returned, allowing it to easily fit in when added
This commit is contained in:
Rishabh 2022-09-13 20:12:36 +05:30
parent c175bd953b
commit 048055bb51
3 changed files with 53 additions and 90 deletions

View File

@ -12,7 +12,7 @@ export default class Recents extends Component {
}
get sources() {
return this.dashboardStats?.membersAttributionSources90d || [];
return this.dashboardStats?.memberSourceAttributionCounts;
}
get areMembersEnabled() {

View File

@ -208,6 +208,8 @@ export default class DashboardMocksService extends Service {
maxPeriod: 90
};
this.memberAttributionStats = [];
for (let index = 0; index < generateDays; index++) {
const date = new Date(startDate.getTime());
date.setDate(date.getDate() + index);
@ -267,6 +269,14 @@ export default class DashboardMocksService extends Service {
paidSubscribed: paidSubscribed1 + paidSubscribed2,
paidCanceled: paidCanceled1 + paidCanceled2
});
const attributionSources = ['Twitter', 'Ghost Network', 'Product Hunt', 'Direct', 'Ghost Newsletter'];
this.memberAttributionStats.push({
date: date.toISOString().split('T')[0],
source: attributionSources[Math.floor(Math.random() * attributionSources.length)],
freeSignups: Math.floor(Math.random() * 50),
paidConversions: Math.floor(Math.random() * 30)
});
}
if (stats.length === 0) {
@ -338,75 +348,6 @@ export default class DashboardMocksService extends Service {
this.membersLastSeen7d = Math.round(Math.random() * currentCounts.free / 2);
this.membersLastSeen30d = this.membersLastSeen7d + Math.round(Math.random() * currentCounts.free / 2);
this.membersAttributionSources7d = [
{
source: 'Twitter',
freeSignups: Math.floor(Math.random() * currentCounts.free / 3),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 3)
},
{
source: 'Ghost Newsletter',
freeSignups: Math.floor(Math.random() * currentCounts.free / 3),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 3)
},
{
source: 'Ghost Network',
freeSignups: Math.floor(Math.random() * currentCounts.free / 3),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 3)
},
{
source: 'Direct',
freeSignups: Math.floor(Math.random() * currentCounts.free / 3),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 3)
}
];
this.membersAttributionSources30d = [
{
source: 'Twitter',
freeSignups: Math.floor(Math.random() * currentCounts.free / 2),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 2)
},
{
source: 'Ghost Newsletter',
freeSignups: Math.floor(Math.random() * currentCounts.free / 2),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 2)
},
{
source: 'Ghost Network',
freeSignups: Math.floor(Math.random() * currentCounts.free / 2),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 2)
},
{
source: 'Direct',
freeSignups: Math.floor(Math.random() * currentCounts.free / 2),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 2)
}
];
this.membersAttributionSources90d = [
{
source: 'Twitter',
freeSignups: Math.floor(Math.random() * currentCounts.free / 20),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 20)
},
{
source: 'Ghost Newsletter',
freeSignups: Math.floor(Math.random() * currentCounts.free / 20),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 20)
},
{
source: 'Ghost Network',
freeSignups: Math.floor(Math.random() * currentCounts.free / 20),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 20)
},
{
source: 'Direct',
freeSignups: Math.floor(Math.random() * currentCounts.free / 20),
paidConversions: Math.floor(Math.random() * currentCounts.paid / 20)
}
];
this.emailOpenRateStats = [];
if (days >= 7) {
this.emailOpenRateStats.push(

View File

@ -24,6 +24,15 @@ import {tracked} from '@glimmer/tracking';
/**
* @typedef AttributionCountStat
* @type {Object}
* @property {string} date The date (YYYY-MM-DD) on which these counts were recorded
* @property {number} source Attribution Source
* @property {number} freeSignups Total free members signed up for this source
* @property {number} paidConversions Total paid conversions for this source
*/
/**
* @typedef SourceAttributionCounts
* @type {Object}
* @property {number} source Attribution Source
* @property {number} freeSignups Total free members signed up for this source
* @property {number} paidConversions Total paid conversions for this source
@ -116,22 +125,10 @@ export default class DashboardStatsService extends Service {
membersLastSeen30d = null;
/**
* @type {AttributionCountStat[]} Count of Attribution sources in last 7 days
*/
@tracked
membersAttributionSources7d = null;
/**
* @type {AttributionCountStat[]} Count of Attribution sources in last 30 days
*/
@tracked
membersAttributionSources30d = null;
/**
* @type {AttributionCountStat[]} Count of Attribution sources in last 90 days
* @type {AttributionCountStat[]} Count of all attribution sources by date
*/
@tracked
membersAttributionSources90d = null;
memberAttributionStats = null;
/**
* @type {?number} Number of members last seen in last 7 days (could differ if filtered by member status)
@ -235,6 +232,35 @@ export default class DashboardStatsService extends Service {
};
}
/**
* @type {?SourceAttributionCounts}
*/
get memberSourceAttributionCounts() {
if (!this.memberAttributionStats) {
return [];
}
return this.memberAttributionStats.filter((stat) => {
if (this.chartDays === 'all') {
return true;
}
return stat.date >= moment().add(-this.chartDays, 'days').format('YYYY-MM-DD');
}).reduce((acc, stat) => {
const existingSource = acc.find(s => s.source === stat.source);
if (existingSource) {
existingSource.freeSignups += stat.freeSignups || 0;
existingSource.paidConversions += stat.paidConversions || 0;
} else {
acc.push({
source: stat.source,
freeSignups: stat.freeSignups || 0,
paidConversions: stat.paidConversions || 0
});
}
return acc;
}, []);
}
get currentMRRTrend() {
if (!this.mrrStats) {
return null;
@ -515,15 +541,11 @@ export default class DashboardStatsService extends Service {
*/
@task
*_loadMemberAttributionStats() {
this.membersAttributionSources7d = null;
this.membersAttributionSources30d = null;
this.membersAttributionSources90d = null;
this.memberAttributionStats = null;
if (this.dashboardMocks.enabled) {
yield this.dashboardMocks.waitRandom();
this.membersAttributionSources7d = this.dashboardMocks.membersAttributionSources7d;
this.membersAttributionSources30d = this.dashboardMocks.membersAttributionSources30d;
this.membersAttributionSources90d = this.dashboardMocks.membersAttributionSources90d;
this.memberAttributionStats = this.dashboardMocks.memberAttributionStats;
return;
}
return;