/* global Chart */ import Component from '@glimmer/component'; import moment from 'moment'; import {getSymbol} from 'ghost-admin/utils/currency'; import {ghPriceAmount} from '../../../../helpers/gh-price-amount'; import {inject as service} from '@ember/service'; const DATE_FORMAT = 'D MMM, YYYY'; // custom ChartJS draw function Chart.defaults.hoverLine = Chart.defaults.line; Chart.controllers.hoverLine = Chart.controllers.line.extend({ draw: function (ease) { Chart.controllers.line.prototype.draw.call(this, ease); if (this.chart.tooltip._active && this.chart.tooltip._active.length) { let activePoint = this.chart.tooltip._active[0], ctx = this.chart.ctx, x = activePoint.tooltipPosition().x, topY = this.chart.legend.bottom, bottomY = this.chart.chartArea.bottom; // draw line ctx.save(); ctx.beginPath(); ctx.moveTo(x, topY); ctx.lineTo(x, bottomY); ctx.setLineDash([3, 4]); ctx.lineWidth = 1; ctx.strokeStyle = '#7C8B9A'; ctx.stroke(); ctx.restore(); } } }); export default class Mrr extends Component { @service dashboardStats; @service feature; get loading() { return this.dashboardStats.mrrStats === null; } get currentMRR() { return this.dashboardStats.currentMRR ?? 0; } get mrrTrend() { return this.calculatePercentage(this.dashboardStats.currentMRRTrend, this.dashboardStats.currentMRR); } get hasTrends() { return this.dashboardStats.currentMRR !== null && this.dashboardStats.currentMRRTrend !== null; } get chartTitle() { return 'MRR'; } get chartType() { return 'hoverLine'; // uses custom ChartJS draw function } get totalMembers() { return this.dashboardStats.memberCounts?.total ?? 0; } get isTotalMembersZero() { return this.dashboardStats.memberCounts && this.totalMembers === 0; } get mrrCurrencySymbol() { if (this.dashboardStats.mrrStats === null) { return ''; } const firstCurrency = this.dashboardStats.mrrStats[0] ? this.dashboardStats.mrrStats[0].currency : 'usd'; return getSymbol(firstCurrency); } get currentMRRFormatted() { // fake empty data if (this.isTotalMembersZero) { return '$123'; } if (this.dashboardStats.mrrStats === null) { return '-'; } const valueText = ghPriceAmount(this.currentMRR, {cents: false}); return `${this.mrrCurrencySymbol}${valueText}`; } get chartData() { let stats = this.dashboardStats.filledMrrStats; let labels = stats.map(stat => stat.date); let data = stats.map(stat => stat.mrr); console.log('this.isTotalMembersZero', this.isTotalMembersZero); // 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 fill const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const gradient = ctx.createLinearGradient(0, 0, 0, 120); gradient.addColorStop(0, 'rgba(143, 66, 255, 0.15'); gradient.addColorStop(1, 'rgba(143, 66, 255, 0.0'); return { labels: labels, datasets: [{ data: data, tension: 0, cubicInterpolationMode: 'monotone', fill: true, fillColor: gradient, backgroundColor: gradient, pointRadius: 0, pointHitRadius: 10, pointBorderColor: '#8E42FF', pointBackgroundColor: '#8E42FF', pointHoverBackgroundColor: '#8E42FF', pointHoverBorderColor: '#8E42FF', pointHoverRadius: 0, borderColor: '#8E42FF', borderJoinStyle: 'miter' }] }; } get chartOptions() { const that = this; const barColor = this.feature.nightShift ? 'rgba(200, 204, 217, 0.25)' : 'rgba(200, 204, 217, 0.65)'; return { responsive: true, maintainAspectRatio: false, title: { display: false }, legend: { display: false }, layout: { padding: { top: 2, bottom: 2, left: 0, right: 0 } }, hover: { onHover: function (e) { e.target.style.cursor = 'pointer'; } }, animation: { duration: 0 }, responsiveAnimationDuration: 0, tooltips: { enabled: false, intersect: false, mode: 'index', custom: function (tooltip) { // get tooltip element const tooltipEl = document.getElementById('gh-dashboard5-mrr-tooltip'); // only show tooltip when active if (tooltip.opacity === 0) { tooltipEl.style.display = 'none'; tooltipEl.style.opacity = 0; return; } // update tooltip styles tooltipEl.style.display = 'block'; tooltipEl.style.opacity = 1; tooltipEl.style.position = 'absolute'; tooltipEl.style.left = tooltip.x + 'px'; tooltipEl.style.top = tooltip.y + 'px'; }, callbacks: { label: (tooltipItems, data) => { const value = `${that.mrrCurrencySymbol}${ghPriceAmount(data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index])}`; document.querySelector('#gh-dashboard5-mrr-tooltip .gh-dashboard5-tooltip-value').innerHTML = value; }, title: (tooltipItems) => { const value = moment(tooltipItems[0].xLabel).format(DATE_FORMAT); document.querySelector('#gh-dashboard5-mrr-tooltip .gh-dashboard5-tooltip-label').innerHTML = value; } } }, scales: { yAxes: [{ display: true, gridLines: { drawTicks: false, display: false, drawBorder: false, color: 'transparent', zeroLineColor: barColor, zeroLineWidth: 1 }, ticks: { display: false } }], xAxes: [{ display: true, scaleLabel: { align: 'start' }, gridLines: { color: barColor, borderDash: [4,4], display: false, drawBorder: true, drawTicks: false, zeroLineWidth: 1, zeroLineColor: barColor, zeroLineBorderDash: [4,4] }, ticks: { display: false, beginAtZero: true } }] } }; } // used for empty state get emptyData() { return { stats: [ { "date": "2022-04-07", "mrr": 0, "currency": "usd" }, { "date": "2022-04-08", "mrr": 0, "currency": "usd" }, { "date": "2022-04-09", "mrr": 1500, "currency": "usd" }, { "date": "2022-04-10", "mrr": 2000, "currency": "usd" }, { "date": "2022-04-11", "mrr": 4500, "currency": "usd" }, { "date": "2022-04-12", "mrr": 7500, "currency": "usd" }, { "date": "2022-04-13", "mrr": 11000, "currency": "usd" }, { "date": "2022-04-14", "mrr": 12500, "currency": "usd" }, { "date": "2022-04-15", "mrr": 14500, "currency": "usd" }, { "date": "2022-04-16", "mrr": 18000, "currency": "usd" }, { "date": "2022-04-17", "mrr": 21500, "currency": "usd" }, { "date": "2022-04-18", "mrr": 25000, "currency": "usd" }, { "date": "2022-04-19", "mrr": 28000, "currency": "usd" }, { "date": "2022-04-20", "mrr": 30000, "currency": "usd" }, { "date": "2022-04-21", "mrr": 34000, "currency": "usd" }, { "date": "2022-04-22", "mrr": 35000, "currency": "usd" }, { "date": "2022-04-23", "mrr": 35500, "currency": "usd" }, { "date": "2022-04-24", "mrr": 37000, "currency": "usd" }, { "date": "2022-04-25", "mrr": 38000, "currency": "usd" }, { "date": "2022-04-26", "mrr": 40500, "currency": "usd" }, { "date": "2022-04-27", "mrr": 43500, "currency": "usd" }, { "date": "2022-04-28", "mrr": 47000, "currency": "usd" }, { "date": "2022-04-29", "mrr": 48000, "currency": "usd" }, { "date": "2022-04-30", "mrr": 50500, "currency": "usd" }, { "date": "2022-05-01", "mrr": 53500, "currency": "usd" }, { "date": "2022-05-02", "mrr": 55000, "currency": "usd" }, { "date": "2022-05-03", "mrr": 56500, "currency": "usd" }, { "date": "2022-05-04", "mrr": 57000, "currency": "usd" }, { "date": "2022-05-05", "mrr": 58000, "currency": "usd" }, { "date": "2022-05-06", "mrr": 58500, "currency": "usd" } ], 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: [ 0, 1500, 4000, 5000, 9000, 11500, 22500, 26000, 30000, 30000, 31000, 33000, 33500, 35500, 36500, 36500, 40000, 40500, 43500, 47000, 49000, 49500, 50000, 50000, 53000, 56000, 58000, 61000, 63500, 63500 ] } } calculatePercentage(from, to) { if (from === 0) { if (to > 0) { return 100; } return 0; } return Math.round((to - from) / from * 100); } }