/* * This file is part of Flarum. * * (c) Toby Zerner * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ import DashboardWidget from 'flarum/components/DashboardWidget'; import SelectDropdown from 'flarum/components/SelectDropdown'; import Button from 'flarum/components/Button'; import icon from 'flarum/helpers/icon'; import abbreviateNumber from 'flarum/utils/abbreviateNumber'; import { Chart } from 'frappe-charts/dist/frappe-charts.esm.js'; export default class StatisticsWidget extends DashboardWidget { init() { super.init(); // Create a Date object which represents the start of the day in the // configured timezone. To do this we convert a UTC time into that timezone, // reset to the first hour of the day, and then convert back into UTC time. // We'll be working with seconds rather than milliseconds throughout too. let today = new Date(); today.setTime(today.getTime() + app.data.statistics.timezoneOffset * 1000); today.setUTCHours(0, 0, 0, 0); today.setTime(today.getTime() - app.data.statistics.timezoneOffset * 1000); today = today / 1000; this.entities = ['users', 'discussions', 'posts']; this.periods = { today: {start: today, end: today + 86400, step: 3600}, last_7_days: {start: today - 86400 * 7, end: today, step: 86400}, last_28_days: {start: today - 86400 * 28, end: today, step: 86400}, last_12_months: {start: today - 86400 * 364, end: today, step: 86400 * 7} }; this.selectedEntity = 'users'; this.selectedPeriod = 'last_7_days'; } className() { return 'StatisticsWidget'; } content() { const thisPeriod = this.periods[this.selectedPeriod]; return (
{app.translator.trans('flarum-statistics.admin.statistics.total_label')}
{Object.keys(this.periods).map(period => ( ))}
{this.entities.map(entity => { const totalCount = this.getTotalCount(entity); const thisPeriodCount = this.getPeriodCount(entity, thisPeriod); const lastPeriodCount = this.getPeriodCount(entity, this.getLastPeriod(thisPeriod)); const periodChange = lastPeriodCount > 0 && (thisPeriodCount - lastPeriodCount) / lastPeriodCount * 100; return (

{app.translator.trans('flarum-statistics.admin.statistics.'+entity+'_heading')}

{abbreviateNumber(totalCount)}
{abbreviateNumber(thisPeriodCount)}{' '} {periodChange ? ( 0 ? 'up' : 'down')}> {icon('fas fa-arrow-'+(periodChange > 0 ? 'up' : 'down'))} {Math.abs(periodChange.toFixed(1))}% ) : ''}
); })}
); } drawChart(elm, isInitialized, context) { if (context.chart && context.entity === this.selectedEntity && context.period === this.selectedPeriod) { return; } const offset = app.data.statistics.timezoneOffset; const period = this.periods[this.selectedPeriod]; const periodLength = period.end - period.start; const labels = []; const thisPeriod = []; const lastPeriod = []; for (let i = period.start; i < period.end; i += period.step) { let label; if (period.step < 86400) { label = moment.unix(i + offset).utc().format('h A'); } else { label = moment.unix(i + offset).utc().format('D MMM'); if (period.step > 86400) { label += ' - ' + moment.unix(i + offset + period.step - 1).utc().format('D MMM'); } } labels.push(label); thisPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i, end: i + period.step})); lastPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i - periodLength, end: i - periodLength + period.step})); } const datasets = [ {values: lastPeriod}, {values: thisPeriod} ]; const data = { labels, datasets }; if (!context.chart) { context.chart = new Chart(elm, { data, type: 'line', height: 280, axisOptions: { xAxisMode: 'tick', yAxisMode: 'span', xIsSeries: true }, lineOptions: { hideDots: 1 }, colors: ['black', app.forum.attribute('themePrimaryColor')] }); } else { context.chart.update(data); } context.entity = this.selectedEntity; context.period = this.selectedPeriod; } changeEntity(entity) { this.selectedEntity = entity; } changePeriod(period) { this.selectedPeriod = period; } getTotalCount(entity) { return app.data.statistics[entity].total; } getPeriodCount(entity, period) { const timed = app.data.statistics[entity].timed; let count = 0; for (const time in timed) { if (time >= period.start && time < period.end) { count += timed[time]; } } return count; } getLastPeriod(thisPeriod) { return { start: thisPeriod.start - (thisPeriod.end - thisPeriod.start), end: thisPeriod.start }; } }