Basic working empty state for the anchor chart when there are 0 members

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

- has new loading checks to see if there are 0 members
- has a blurred overlay box that works over the top of the anchor chart
- styles are still not perfect but work well enough for the mo
This commit is contained in:
James Morris 2022-05-06 16:19:16 +01:00
parent c36a5bbaeb
commit 8af605babe
7 changed files with 475 additions and 3 deletions

View File

@ -14,6 +14,10 @@ export default class DashboardDashboardV5Component extends Component {
return this.dashboardStats.siteStatus === null; return this.dashboardStats.siteStatus === null;
} }
get totalMembers() {
return this.dashboardStats.memberCounts?.total ?? 0;
}
get hasPaidTiers() { get hasPaidTiers() {
return this.dashboardStats.siteStatus?.hasPaidTiers; return this.dashboardStats.siteStatus?.hasPaidTiers;
} }

View File

@ -82,4 +82,14 @@
</div> </div>
</article> </article>
{{#if this.isTotalMembersZero}}
<div class="gh-dashboard5-anchor-empty">
<div class="gh-dashboard5-anchor-empty-message">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.a{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}</style></defs><title>graph-stats-ascend</title><polyline class="a" points="23.25 12.75 23.25 6 16.5 6"/><path class="a" d="M23.25,6l-7.939,7.939a1.5,1.5,0,0,1-2.122,0l-3.128-3.128a1.5,1.5,0,0,0-2.122,0L.75,18"/></svg>
<h4>Get your first member to unlock analytics!</h4>
<p>Analytics will appear here as soon as someone subscribes to your site.</p>
</div>
</div>
{{/if}}
</section> </section>

View File

@ -65,6 +65,7 @@ export default class Anchor extends Component {
@service dashboardStats; @service dashboardStats;
@service feature; @service feature;
@tracked chartDisplay = 'total'; @tracked chartDisplay = 'total';
@tracked totalMembersOverall = null;
daysOptions = DAYS_OPTIONS; daysOptions = DAYS_OPTIONS;
displayOptions = DISPLAY_OPTIONS; displayOptions = DISPLAY_OPTIONS;
@ -81,6 +82,8 @@ export default class Anchor extends Component {
loadCharts() { loadCharts() {
this.dashboardStats.loadMemberCountStats(); this.dashboardStats.loadMemberCountStats();
console.log('this.dashboardStats.memberCounts', this.dashboardStats.memberCounts);
if (this.hasPaidTiers) { if (this.hasPaidTiers) {
this.dashboardStats.loadMrrStats(); this.dashboardStats.loadMrrStats();
} }
@ -112,6 +115,14 @@ export default class Anchor extends Component {
return this.dashboardStats.memberCounts?.total ?? 0; return this.dashboardStats.memberCounts?.total ?? 0;
} }
get isTotalMembersZero() {
return this.dashboardStats.memberCounts && this.totalMembers === 0;
}
get isTotalMembersMoreThanZero() {
return this.dashboardStats.memberCounts && this.totalMembers > 0;
}
get paidMembers() { get paidMembers() {
return this.dashboardStats.memberCounts?.paid ?? 0; return this.dashboardStats.memberCounts?.paid ?? 0;
} }
@ -179,6 +190,13 @@ export default class Anchor extends Component {
data = stats.map(stat => stat.paid + stat.free + stat.comped); data = stats.map(stat => stat.paid + stat.free + stat.comped);
} }
// with no members yet, let's show empty state with dummy data
if (this.isTotalMembersZero) {
stats = this.emptyData.stats;
labels = this.emptyData.labels;
data = this.emptyData.data;
}
// gradient for line // gradient for line
const canvasLine = document.createElement('canvas'); const canvasLine = document.createElement('canvas');
const ctxLine = canvasLine.getContext('2d'); const ctxLine = canvasLine.getContext('2d');
@ -193,6 +211,11 @@ export default class Anchor extends Component {
gradientFill.addColorStop(0, 'rgba(250, 45, 142, 0.2'); gradientFill.addColorStop(0, 'rgba(250, 45, 142, 0.2');
gradientFill.addColorStop(1, 'rgba(143, 66, 255, 0.02'); gradientFill.addColorStop(1, 'rgba(143, 66, 255, 0.02');
// fake data
console.log('stats', stats);
console.log('labels', labels);
console.log('data', data);
return { return {
labels: labels, labels: labels,
datasets: [{ datasets: [{
@ -345,6 +368,378 @@ export default class Anchor extends Component {
return 180; return 180;
} }
// used for empty state
get emptyData() {
return {
stats: [
{
"date": "2022-04-07",
"free": 2610,
"tier1": 295,
"tier2": 20,
"paid": 315,
"comped": 0,
"paidSubscribed": 2,
"paidCanceled": 1
},
{
"date": "2022-04-08",
"free": 2765,
"tier1": 298,
"tier2": 24,
"paid": 322,
"comped": 0,
"paidSubscribed": 7,
"paidCanceled": 0
},
{
"date": "2022-04-09",
"free": 3160,
"tier1": 299,
"tier2": 28,
"paid": 327,
"comped": 0,
"paidSubscribed": 5,
"paidCanceled": 0
},
{
"date": "2022-04-10",
"free": 3580,
"tier1": 300,
"tier2": 30,
"paid": 330,
"comped": 0,
"paidSubscribed": 4,
"paidCanceled": 1
},
{
"date": "2022-04-11",
"free": 3583,
"tier1": 301,
"tier2": 31,
"paid": 332,
"comped": 0,
"paidSubscribed": 2,
"paidCanceled": 0
},
{
"date": "2022-04-12",
"free": 3857,
"tier1": 303,
"tier2": 36,
"paid": 339,
"comped": 0,
"paidSubscribed": 8,
"paidCanceled": 1
},
{
"date": "2022-04-13",
"free": 4223,
"tier1": 304,
"tier2": 39,
"paid": 343,
"comped": 0,
"paidSubscribed": 4,
"paidCanceled": 0
},
{
"date": "2022-04-14",
"free": 4289,
"tier1": 306,
"tier2": 42,
"paid": 348,
"comped": 0,
"paidSubscribed": 6,
"paidCanceled": 1
},
{
"date": "2022-04-15",
"free": 4458,
"tier1": 307,
"tier2": 49,
"paid": 356,
"comped": 0,
"paidSubscribed": 8,
"paidCanceled": 0
},
{
"date": "2022-04-16",
"free": 4752,
"tier1": 307,
"tier2": 49,
"paid": 356,
"comped": 0,
"paidSubscribed": 1,
"paidCanceled": 1
},
{
"date": "2022-04-17",
"free": 4947,
"tier1": 310,
"tier2": 50,
"paid": 360,
"comped": 0,
"paidSubscribed": 5,
"paidCanceled": 1
},
{
"date": "2022-04-18",
"free": 5047,
"tier1": 312,
"tier2": 49,
"paid": 361,
"comped": 0,
"paidSubscribed": 2,
"paidCanceled": 1
},
{
"date": "2022-04-19",
"free": 5430,
"tier1": 314,
"tier2": 55,
"paid": 369,
"comped": 0,
"paidSubscribed": 8,
"paidCanceled": 0
},
{
"date": "2022-04-20",
"free": 5760,
"tier1": 316,
"tier2": 57,
"paid": 373,
"comped": 0,
"paidSubscribed": 4,
"paidCanceled": 0
},
{
"date": "2022-04-21",
"free": 6022,
"tier1": 318,
"tier2": 63,
"paid": 381,
"comped": 0,
"paidSubscribed": 9,
"paidCanceled": 1
},
{
"date": "2022-04-22",
"free": 6294,
"tier1": 319,
"tier2": 64,
"paid": 383,
"comped": 0,
"paidSubscribed": 2,
"paidCanceled": 0
},
{
"date": "2022-04-23",
"free": 6664,
"tier1": 320,
"tier2": 69,
"paid": 389,
"comped": 0,
"paidSubscribed": 6,
"paidCanceled": 0
},
{
"date": "2022-04-24",
"free": 6721,
"tier1": 320,
"tier2": 70,
"paid": 390,
"comped": 0,
"paidSubscribed": 1,
"paidCanceled": 0
},
{
"date": "2022-04-25",
"free": 6841,
"tier1": 321,
"tier2": 80,
"paid": 401,
"comped": 0,
"paidSubscribed": 11,
"paidCanceled": 0
},
{
"date": "2022-04-26",
"free": 6880,
"tier1": 323,
"tier2": 89,
"paid": 412,
"comped": 0,
"paidSubscribed": 11,
"paidCanceled": 0
},
{
"date": "2022-04-27",
"free": 7179,
"tier1": 325,
"tier2": 92,
"paid": 417,
"comped": 0,
"paidSubscribed": 5,
"paidCanceled": 0
},
{
"date": "2022-04-28",
"free": 7288,
"tier1": 325,
"tier2": 100,
"paid": 425,
"comped": 0,
"paidSubscribed": 9,
"paidCanceled": 1
},
{
"date": "2022-04-29",
"free": 7430,
"tier1": 325,
"tier2": 101,
"paid": 426,
"comped": 0,
"paidSubscribed": 2,
"paidCanceled": 1
},
{
"date": "2022-04-30",
"free": 7458,
"tier1": 326,
"tier2": 102,
"paid": 428,
"comped": 0,
"paidSubscribed": 2,
"paidCanceled": 0
},
{
"date": "2022-05-01",
"free": 7621,
"tier1": 327,
"tier2": 117,
"paid": 444,
"comped": 0,
"paidSubscribed": 17,
"paidCanceled": 1
},
{
"date": "2022-05-02",
"free": 7721,
"tier1": 328,
"tier2": 123,
"paid": 451,
"comped": 0,
"paidSubscribed": 8,
"paidCanceled": 1
},
{
"date": "2022-05-03",
"free": 7897,
"tier1": 327,
"tier2": 137,
"paid": 464,
"comped": 0,
"paidSubscribed": 14,
"paidCanceled": 1
},
{
"date": "2022-05-04",
"free": 7937,
"tier1": 327,
"tier2": 143,
"paid": 470,
"comped": 0,
"paidSubscribed": 6,
"paidCanceled": 0
},
{
"date": "2022-05-05",
"free": 7961,
"tier1": 328,
"tier2": 158,
"paid": 486,
"comped": 0,
"paidSubscribed": 16,
"paidCanceled": 0
},
{
"date": "2022-05-06",
"free": 8006,
"tier1": 328,
"tier2": 162,
"paid": 490,
"comped": 0,
"paidSubscribed": 5,
"paidCanceled": 1
}
],
labels: [
"2022-04-07",
"2022-04-08",
"2022-04-09",
"2022-04-10",
"2022-04-11",
"2022-04-12",
"2022-04-13",
"2022-04-14",
"2022-04-15",
"2022-04-16",
"2022-04-17",
"2022-04-18",
"2022-04-19",
"2022-04-20",
"2022-04-21",
"2022-04-22",
"2022-04-23",
"2022-04-24",
"2022-04-25",
"2022-04-26",
"2022-04-27",
"2022-04-28",
"2022-04-29",
"2022-04-30",
"2022-05-01",
"2022-05-02",
"2022-05-03",
"2022-05-04",
"2022-05-05",
"2022-05-06"
],
data: [
2925,
3087,
3487,
3910,
3915,
4196,
4566,
4637,
4814,
5108,
5307,
5408,
5799,
6133,
6403,
6677,
7053,
7111,
7242,
7292,
7596,
7713,
7856,
7886,
8065,
8172,
8361,
8407,
8447,
8496
]
}
}
calculatePercentage(from, to) { calculatePercentage(from, to) {
if (from === 0) { if (from === 0) {
if (to > 0) { if (to > 0) {

View File

@ -1,6 +1,5 @@
<section class="gh-dashboard5-section gh-dashboard5-overview"> <section class="gh-dashboard5-section gh-dashboard5-overview {{unless this.isTotalMembersMoreThanZero 'is-hidden'}}">
<article {{did-insert this.loadCharts}} class="gh-dashboard5-box is-secondary"> <article {{did-insert this.loadCharts}} class="gh-dashboard5-box is-secondary">
<div class="gh-dashboard5-columns"> <div class="gh-dashboard5-columns">
<div class="gh-dashboard5-column"> <div class="gh-dashboard5-column">
<Dashboard::v5::Parts::Metric <Dashboard::v5::Parts::Metric
@ -27,6 +26,5 @@
@large={{true}} /> @large={{true}} />
</div> </div>
</div> </div>
</article> </article>
</section> </section>

View File

@ -20,6 +20,14 @@ export default class Overview extends Component {
return this.dashboardStats.memberCounts?.total ?? 0; return this.dashboardStats.memberCounts?.total ?? 0;
} }
get isTotalMembersZero() {
return this.dashboardStats.memberCounts && this.totalMembers === 0;
}
get isTotalMembersMoreThanZero() {
return this.dashboardStats.memberCounts && this.totalMembers > 0;
}
get paidMembers() { get paidMembers() {
return this.dashboardStats.memberCounts?.paid ?? 0; return this.dashboardStats.memberCounts?.paid ?? 0;
} }

View File

@ -757,6 +757,10 @@ Dashboard v5 Overview */
position: relative; position: relative;
} }
.gh-dashboard5-overview.is-hidden {
display: none;
}
.gh-dashboard5-overview .gh-dashboard5-area { .gh-dashboard5-overview .gh-dashboard5-area {
flex-direction: row; flex-direction: row;
padding: 24px; padding: 24px;
@ -874,6 +878,58 @@ Dashboard v5 Anchor */
right: -18px; right: -18px;
} }
.gh-dashboard5-anchor-empty {
position: absolute;
top: 16px;
left: 16px;
width: calc(100% - 32px);
height: calc(100% - 32px);
background: rgba(255,255,255,0.8);
-webkit-backdrop-filter: blur(3px);
backdrop-filter: blur(3px);
display: flex;
align-items: center;
justify-content: center;
}
.gh-dashboard5-anchor-empty-message {
background: #ffffff;
width: 416px;
padding: 32px 48px 48px;
border-radius: 8px;
text-align: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.075);
}
.gh-dashboard5-anchor-empty-message svg {
width: 48px;
height: auto;
margin: 0 0 16px;
fill: red;
}
.gh-dashboard5-anchor-empty-message h4 {
font-size: 1.55rem;
font-weight: 700;
line-height: 1em;
margin: 0 0 12px;
padding: 0;
color: var(--black);
white-space: nowrap;
letter-spacing: -.3px;
}
.gh-dashboard5-anchor-empty-message p {
font-size: 1.2rem;
font-weight: 600;
line-height: 1.4em;
color: var(--black);
letter-spacing: -.1px;
margin: 0;
padding: 0;
}
/* --------------------------------- /* ---------------------------------
Dashboard v5 Engagement */ Dashboard v5 Engagement */

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.a{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}</style></defs><title>graph-stats-ascend</title><polyline class="a" points="23.25 12.75 23.25 6 16.5 6"/><path class="a" d="M23.25,6l-7.939,7.939a1.5,1.5,0,0,1-2.122,0l-3.128-3.128a1.5,1.5,0,0,0-2.122,0L.75,18"/></svg>

After

Width:  |  Height:  |  Size: 387 B