From 99f119a1f4a0f583851e86f52f80490fcc3a5043 Mon Sep 17 00:00:00 2001 From: Djordje Vlaisavljevic Date: Mon, 19 Sep 2022 10:48:24 +0200 Subject: [PATCH] Source attribution design (#15431) - Updated subscription box design - Added Source attribution widget to the dashboard Co-authored-by: Rishabh --- .../dashboard/charts/attribution.hbs | 83 +++++--- .../dashboard/charts/attribution.js | 64 +++++- .../components/gh-member-settings-form.hbs | 195 ++++++++++++++++++ ghost/admin/app/services/dashboard-stats.js | 4 +- ghost/admin/app/styles/layouts/members.css | 84 ++++++++ 5 files changed, 394 insertions(+), 36 deletions(-) diff --git a/ghost/admin/app/components/dashboard/charts/attribution.hbs b/ghost/admin/app/components/dashboard/charts/attribution.hbs index 337a7c126d..513d91d8b3 100644 --- a/ghost/admin/app/components/dashboard/charts/attribution.hbs +++ b/ghost/admin/app/components/dashboard/charts/attribution.hbs @@ -1,41 +1,58 @@
+
-
-
-
Sources
-
Free Signups
-
Paid Conversions
-
-
- {{#each this.sources as |sourceData|}} -
-
- {{sourceData.source}} -
-
+

Source attribution

+
+
+
+
Sources
+
Free Signups
+
Paid Conversions
+
+
+ {{#each this.sources as |sourceData|}} +
+
+ {{sourceData.source}} +
+
+ + {{#if sourceData.freeSignups}} + {{format-number sourceData.freeSignups}} + {{else}} + — + {{/if}} + +
+
- {{#if sourceData.freeSignups}} - {{format-number sourceData.freeSignups}} - {{else}} - — - {{/if}} - + {{#if sourceData.paidConversions}} + {{format-number sourceData.paidConversions}} + {{else}} + — + {{/if}} + +
-
- - {{#if sourceData.paidConversions}} - {{format-number sourceData.paidConversions}} - {{else}} - — - {{/if}} - + {{else}} +
+

No sources.

-
- {{else}} -
-

No sources.

-
- {{/each}} + {{/each}} +
+
+
+
+ +
diff --git a/ghost/admin/app/components/dashboard/charts/attribution.js b/ghost/admin/app/components/dashboard/charts/attribution.js index ea12c90195..3b0a0754ab 100644 --- a/ghost/admin/app/components/dashboard/charts/attribution.js +++ b/ghost/admin/app/components/dashboard/charts/attribution.js @@ -1,18 +1,78 @@ import Component from '@glimmer/component'; import {action} from '@ember/object'; import {inject as service} from '@ember/service'; -// import {tracked} from '@glimmer/tracking'; +import {tracked} from '@glimmer/tracking'; +const CHART_COLORS = [ + '#853EED', + '#CA3FED', + '#E993CC', + '#EE9696', + '#FEC7C0' +]; export default class Recents extends Component { @service dashboardStats; + @tracked chartType = 'free'; @action loadData() { this.dashboardStats.loadMemberAttributionStats(); } + get chartOptions() { + return { + cutoutPercentage: 60, + borderColor: '#555', + legend: { + display: true, + position: 'top', + align: 'start', + labels: { + color: 'rgb(255, 99, 132)', + fontSize: 12, + boxWidth: 10, + padding: 3 + } + } + }; + } + + get chartData() { + if (this.chartType === 'free') { + const sortedByFree = [...this.sources]; + sortedByFree.sort((a, b) => { + return b.freeSignups - a.freeSignups; + }); + return { + labels: sortedByFree.slice(0, 5).map(source => source.source), + datasets: [{ + label: 'Free Signups', + data: sortedByFree.slice(0, 5).map(source => source.freeSignups), + backgroundColor: CHART_COLORS.slice(0, 5), + borderWidth: 2, + borderColor: '#fff' + }] + }; + } else { + const sortedByPaid = [...this.sources]; + sortedByPaid.sort((a, b) => { + return b.paidPercentage - a.paidPercentage; + }); + return { + labels: sortedByPaid.slice(0, 5).map(source => source.source), + datasets: [{ + label: 'Paid Conversions', + data: sortedByPaid.slice(0, 5).map(source => source.paidConversions), + backgroundColor: CHART_COLORS.slice(0, 5), + borderWidth: 2, + borderColor: '#fff' + }] + }; + } + } + get sources() { - return this.dashboardStats?.memberSourceAttributionCounts; + return this.dashboardStats?.memberSourceAttributionCounts || []; } get areMembersEnabled() { diff --git a/ghost/admin/app/components/gh-member-settings-form.hbs b/ghost/admin/app/components/gh-member-settings-form.hbs index 66811b431a..8aa9e62a14 100644 --- a/ghost/admin/app/components/gh-member-settings-form.hbs +++ b/ghost/admin/app/components/gh-member-settings-form.hbs @@ -133,6 +133,200 @@ {{#each this.tiers as |tier|}}
+ {{#if (feature "sourceAttribution")}} +
+ {{#each tier.subscriptions as |sub index|}} +
+
+
+ {{sub.price.currencySymbol}} + {{sub.price.nonDecimalAmount}} +
+
{{if (eq sub.price.interval "year") "yearly" "monthly"}}
+
+
+

+ {{tier.name}} + {{#if (eq sub.status "canceled")}} + Cancelled + {{else if sub.cancel_at_period_end}} + Cancelled + {{else if sub.compExpiry}} + Active + {{else if sub.trialUntil}} + Active + {{else}} + Active + {{/if}} + {{#if (gt tier.subscriptions.length 1)}} + {{tier.subscriptions.length}} subscriptions + {{/if}} +

+
+ {{#if sub.trialUntil}} + Free trial + {{else}} + {{#if (or (eq sub.price.nickname "Monthly") (eq sub.price.nickname "Yearly"))}} + {{else}} + {{sub.price.nickname}} + {{/if}} + {{/if}} + + {{#if (eq sub.status "canceled")}} + Ended {{sub.validUntil}} + {{else if sub.cancel_at_period_end}} + Has access until {{sub.validUntil}} + {{else if sub.compExpiry}} + Expires {{sub.compExpiry}} + {{else if sub.trialUntil}} + Ends {{sub.trialUntil}} + {{else}} + Renews {{sub.validUntil}} + {{/if}} +
+
+ {{#if sub.isComplimentary}} + + + + {{svg-jar "dotdotdot"}} + + + + +
  • + +
  • +
    +
    + {{else}} + + + + {{svg-jar "dotdotdot"}} + + + + +
  • + + View Stripe customer + +
  • +
  • +
  • + + View Stripe subscription + +
  • +
  • + {{#if (not-eq sub.status "canceled")}} + {{#if sub.cancel_at_period_end}} + + {{else}} + + {{/if}} + {{/if}} +
  • +
    +
    + {{/if}} +
    +
    +
    + {{#if sub.cancellationReason}} +
    +

    Cancellation reason

    +
    {{sub.cancellationReason}}
    +
    + {{/if}} + {{#if sub.offer}} + {{#if (eq sub.offer.type "trial")}} +
    +

    Offer

    + {{sub.offer.name}} + – {{sub.offer.amount}} days free +
    + {{else}} +
    +

    Offer

    + {{sub.offer.name}} + {{#if (eq sub.offer.type 'fixed')}} + – {{currency-symbol sub.offer.currency}}{{gh-price-amount sub.offer.amount}} off + {{else}} + – {{sub.offer.amount}}% off + {{/if}} +
    + {{/if}} + {{/if}} +
    +

    Source

    +

    From Social: Twitter + {{#if (and sub.attribution sub.attribution.url sub.attribution.title)}} + , subscribed on {{ sub.attribution.title }} + {{/if}} + on {{sub.startDate}}

    +
    +
    +
    + {{/each}} + + {{#if (eq tier.subscriptions.length 0)}} +
    +
    +
    + Complimentary + Active +
    +
    Created on
    +
    +
    +
    +
    + $ + 0 +
    +
    yearly
    +
    + + + + {{svg-jar "dotdotdot"}} + + + + +
  • + +
  • +
    +
    +
    +
    + {{/if}} +
    + {{else}}

    {{tier.name}} @@ -315,6 +509,7 @@

    {{/if}}
    + {{/if}} {{/each}} diff --git a/ghost/admin/app/services/dashboard-stats.js b/ghost/admin/app/services/dashboard-stats.js index 5f0b99eeb6..9eb2cf3322 100644 --- a/ghost/admin/app/services/dashboard-stats.js +++ b/ghost/admin/app/services/dashboard-stats.js @@ -258,7 +258,9 @@ export default class DashboardStatsService extends Service { }); } return acc; - }, []); + }, []).sort((a, b) => { + return (b.freeSignups + b.paidConversions) - (a.freeSignups - a.paidConversions); + }); } get currentMRRTrend() { diff --git a/ghost/admin/app/styles/layouts/members.css b/ghost/admin/app/styles/layouts/members.css index 40be88923d..f5eabc8949 100644 --- a/ghost/admin/app/styles/layouts/members.css +++ b/ghost/admin/app/styles/layouts/members.css @@ -2406,4 +2406,88 @@ p.gh-members-import-errordetail:first-of-type { .gh-contentfilter-menu:last-of-type { padding-right: 8px; } +} + +/* This needs to be moved once the flag is removed */ +.gh-cp-membertier-attribution.gh-membertier-subscription { + display: block !important; +} + +.gh-cp-membertier-attribution { + position: relative; +} + +.gh-cp-membertier-attribution .gh-tier-card-header { + padding-bottom: 16px; +} + +.gh-cp-membertier-attribution .tier-actions-menu { + top: calc(100% + 6px); +} + +.gh-cp-membertier-attribution .gh-tier-card-price { + border: none !important; + background: #f5f6f6; + padding: 10px !important; + border-radius: 6px; +} + +.gh-cp-membertier-attribution .amount { + font-weight: bold !important; + font-size: 2.4rem !important; +} + +.gh-cp-membertier-attribution .currency-symbol { + font-weight: bold !important; + font-size: 1.4rem !important; +} + +.gh-cp-membertier-attribution .gh-membertier-name { + font-weight: bold !important; + font-size: 2rem !important; +} + +.gh-cp-membertier-attribution .gh-badge { + margin-bottom: -1px !important; + margin-left: 8px; +} + +.gh-cp-membertier-attribution .action-menu { + position: absolute; + top: 24px; + right: 24px; +} + +.gh-cp-membertier-attribution span.archived { + background: #e4e8ec; + color: #7c8b9a; + font-size: 1.2rem; +} + +.gh-cp-membertier-attribution .gh-membertier-advanced { + padding-top: 16px; + border-top:1px solid #ECEEF0; +} + +.gh-cp-membertier-attribution .gh-membertier-advanced h4 { + font-size: 1.1rem; + text-transform: uppercase; + letter-spacing: .03em; + font-weight: 500; + color: #7F8B99; + margin-bottom: 2px; +} + +.gh-cp-membertier-attribution .gh-membertier-details p { + margin: 0; +} + +.gh-cp-membertier-attribution .gh-membertier-details span, .gh-cp-membertier-attribution .gh-membertier-details a { + font-size: 1.4rem; + font-weight: 600; + color: #15171A; +} + +.gh-cp-membertier-attribution .gh-cp-membertier-renewal { + color: #7c8b9a; } \ No newline at end of file