mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-29 13:52:10 +03:00
Implemented referrers stats API on posts' analytics page
refs https://github.com/TryGhost/Team/issues/1921
This commit is contained in:
parent
7437d92d50
commit
7cadaa6378
@ -38,13 +38,13 @@ export default class SourceAttributionChart extends Component {
|
||||
if (this.chartType === 'free') {
|
||||
const sortedByFree = [...this.sources];
|
||||
sortedByFree.sort((a, b) => {
|
||||
return b.freeSignups - a.freeSignups;
|
||||
return b.signups - a.signups;
|
||||
});
|
||||
return {
|
||||
labels: sortedByFree.slice(0, 5).map(source => source.source),
|
||||
datasets: [{
|
||||
label: 'Free Signups',
|
||||
data: sortedByFree.slice(0, 5).map(source => source.freeSignups),
|
||||
data: sortedByFree.slice(0, 5).map(source => source.signups),
|
||||
backgroundColor: CHART_COLORS.slice(0, 5),
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff'
|
||||
|
@ -12,8 +12,8 @@
|
||||
</div>
|
||||
<div class="gh-dashboard-list-item-sub">
|
||||
<span class="gh-dashboard-metric-minivalue">
|
||||
{{#if sourceData.freeSignups}}
|
||||
{{format-number sourceData.freeSignups}}
|
||||
{{#if sourceData.signups}}
|
||||
{{format-number sourceData.signups}}
|
||||
{{else}}
|
||||
—
|
||||
{{/if}}
|
||||
|
@ -1,34 +1,45 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
/**
|
||||
* @typedef {import('../../services/dashboard-stats').SourceAttributionCount} SourceAttributionCount
|
||||
*/
|
||||
|
||||
export default class AnalyticsController extends Controller {
|
||||
@service ajax;
|
||||
@service ghostPaths;
|
||||
|
||||
@tracked sources = null;
|
||||
|
||||
get post() {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {SourceAttributionCount[]} - array of objects with source and count properties
|
||||
*/
|
||||
get sources() {
|
||||
return [
|
||||
{
|
||||
source: 'Twitter',
|
||||
freeSignups: 12,
|
||||
paidConversions: 50
|
||||
},
|
||||
{
|
||||
source: 'Google',
|
||||
freeSignups: 9,
|
||||
paidConversions: 32
|
||||
},
|
||||
{
|
||||
source: 'Direct',
|
||||
freeSignups: 2,
|
||||
paidConversions: 40
|
||||
}
|
||||
];
|
||||
@action
|
||||
loadData() {
|
||||
this.fetchReferrersStats();
|
||||
}
|
||||
|
||||
async fetchReferrersStats() {
|
||||
if (this._fetchReferrersStats.isRunning) {
|
||||
return this._fetchReferrersStats.last;
|
||||
}
|
||||
return this._fetchReferrersStats.perform();
|
||||
}
|
||||
|
||||
@task
|
||||
*_fetchReferrersStats() {
|
||||
let statsUrl = this.ghostPaths.url.api(`stats/referrers/posts/${this.post.id}`);
|
||||
let result = yield this.ajax.request(statsUrl);
|
||||
this.sources = result.stats.map((stat) => {
|
||||
return {
|
||||
source: stat.source ?? 'Direct',
|
||||
signups: stat.signups,
|
||||
paidConversions: stat.paid_conversions
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ export default class DashboardMocksService extends Service {
|
||||
this.memberAttributionStats.push({
|
||||
date: date.toISOString().split('T')[0],
|
||||
source: attributionSources[Math.floor(Math.random() * attributionSources.length)],
|
||||
freeSignups: Math.floor(Math.random() * 50),
|
||||
signups: Math.floor(Math.random() * 50),
|
||||
paidConversions: Math.floor(Math.random() * 30)
|
||||
});
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import {tracked} from '@glimmer/tracking';
|
||||
* @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} signups Total free members signed up for this source
|
||||
* @property {number} paidConversions Total paid conversions for this source
|
||||
*/
|
||||
|
||||
@ -34,7 +34,7 @@ import {tracked} from '@glimmer/tracking';
|
||||
* @typedef SourceAttributionCount
|
||||
* @type {Object}
|
||||
* @property {string} source Attribution Source
|
||||
* @property {number} freeSignups Total free members signed up for this source
|
||||
* @property {number} signups Total free members signed up for this source
|
||||
* @property {number} paidConversions Total paid conversions for this source
|
||||
*/
|
||||
|
||||
@ -248,18 +248,18 @@ export default class DashboardStatsService extends Service {
|
||||
}).reduce((acc, stat) => {
|
||||
const existingSource = acc.find(s => s.source === stat.source);
|
||||
if (existingSource) {
|
||||
existingSource.freeSignups += stat.freeSignups || 0;
|
||||
existingSource.signups += stat.signups || 0;
|
||||
existingSource.paidConversions += stat.paidConversions || 0;
|
||||
} else {
|
||||
acc.push({
|
||||
source: stat.source,
|
||||
freeSignups: stat.freeSignups || 0,
|
||||
signups: stat.signups || 0,
|
||||
paidConversions: stat.paidConversions || 0
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []).sort((a, b) => {
|
||||
return (b.freeSignups + b.paidConversions) - (a.freeSignups - a.paidConversions);
|
||||
return (b.signups + b.paidConversions) - (a.signups - a.paidConversions);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -86,23 +86,25 @@
|
||||
</div>
|
||||
|
||||
{{#if (feature 'sourceAttribution')}}
|
||||
<h4 class="gh-main-section-header small bn">
|
||||
<h4 class="gh-main-section-header small bn" {{did-insert this.loadData}}>
|
||||
Source attribution
|
||||
</h4>
|
||||
<div class="gh-post-analytics-box resources">
|
||||
<div style="display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
grid-gap: 64px;
|
||||
">
|
||||
<MemberAttribution::SourceAttributionTable @sources={{this.sources}} />
|
||||
{{#if this.sources}}
|
||||
<div class="gh-post-analytics-box resources">
|
||||
<div style="display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
grid-gap: 64px;
|
||||
">
|
||||
<MemberAttribution::SourceAttributionTable @sources={{this.sources}} />
|
||||
|
||||
<div style="border-left: 1px solid #eceef0; padding-left: 48px;display: flex;justify-content: center;align-items: center;">
|
||||
<div style="max-width: 200px;">
|
||||
<MemberAttribution::SourceAttributionChart @sources={{this.sources}} />
|
||||
<div style="border-left: 1px solid #eceef0; padding-left: 48px;display: flex;justify-content: center;align-items: center;">
|
||||
<div style="max-width: 200px;">
|
||||
<MemberAttribution::SourceAttributionChart @sources={{this.sources}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<h4 class="gh-main-section-header small bn">
|
||||
|
Loading…
Reference in New Issue
Block a user