analytics/assets/js/dashboard/stats/reports/metrics.js

227 lines
5.4 KiB
JavaScript

import React from 'react'
import MetricValue from './metric-value'
import { hasConversionGoalFilter } from '../../util/filters'
// Class representation of a metric.
// Metric instances can be created directly via the Metric constructor,
// or using special creator functions like `createVisitors`, which just
// fill out the known fields for that metric.
// ### Required props
// * `key` - the key under which to read values under in an API
// * `formatter` - a function that takes a value of this metric, and
// and returns the "rendered" version of it. Can be JSX or a string.
// * `renderLabel` - a function rendering a label for this metric given a
// query argument. Returns string.
// ### Optional props
// * `meta` - a map with extra context for this metric. E.g. `plot`, or
// `hiddenOnMobile` define some special behaviours in the context where
// it's used.
export class Metric {
constructor(props) {
if (!props.key) {
throw Error('Required field `key` is missing')
}
if (typeof props.renderLabel !== 'function') {
throw Error('Required field `renderLabel` should be a function')
}
this.key = props.key
this.meta = props.meta || {}
this.sortable = props.sortable
this.width = props.width ?? 'w-24'
this.formatter = props.formatter
this.renderLabel = props.renderLabel
this.renderValue = this.renderValue.bind(this)
}
renderValue(listItem, meta, options = {}) {
const { detailedView = false, isRowHovered = false } = options
return (
<MetricValue
listItem={listItem}
metric={this.key}
renderLabel={this.renderLabel}
meta={meta}
formatter={this.formatter}
detailedView={detailedView}
isRowHovered={isRowHovered}
/>
)
}
}
// Creates a Metric class representing the `visitors` metric.
// Optional props for conveniently generating the `renderLabel` function:
// * `defaultLabel` - label when not realtime, and no goal filter applied
// * `realtimeLabel` - label when realtime period
// * `goalFilterLabel` - label when goal filter is applied
export const createVisitors = (props) => {
let renderLabel
if (typeof props.renderLabel === 'function') {
renderLabel = props.renderLabel
} else {
renderLabel = (query) => {
const defaultLabel = props.defaultLabel || 'Visitors'
const realtimeLabel = props.realtimeLabel || 'Current visitors'
const goalFilterLabel = props.goalFilterLabel || 'Conversions'
if (query.period === 'realtime') {
return realtimeLabel
}
if (query && hasConversionGoalFilter(query)) {
return goalFilterLabel
}
return defaultLabel
}
}
return new Metric({
width: 'w-36',
sortable: true,
...props,
key: 'visitors',
renderLabel
})
}
export const createConversionRate = (props) => {
const renderLabel = (_query) => 'CR'
return new Metric({
width: 'w-28 md:w-24',
...props,
key: 'conversion_rate',
renderLabel,
sortable: true
})
}
export const createPercentage = (props) => {
const renderLabel = (_query) => '%'
return new Metric({
width: 'w-24',
...props,
key: 'percentage',
renderLabel,
sortable: true
})
}
export const createEvents = (props) => {
return new Metric({ width: 'w-28', ...props, key: 'events', sortable: true })
}
export const createTotalRevenue = (props) => {
const renderLabel = (_query) => 'Revenue'
return new Metric({
width: 'w-32',
...props,
key: 'total_revenue',
renderLabel,
sortable: true
})
}
export const createAverageRevenue = (props) => {
const renderLabel = (_query) => 'Average'
return new Metric({
width: 'w-28',
...props,
key: 'average_revenue',
renderLabel,
sortable: true
})
}
export const createTotalVisitors = (props) => {
const renderLabel = (_query) => 'Total visitors'
return new Metric({
width: 'w-32',
...props,
key: 'total_visitors',
renderLabel,
sortable: false
})
}
export const createVisits = (props) => {
return new Metric({ width: 'w-24', sortable: true, ...props, key: 'visits' })
}
export const createVisitDuration = (props) => {
const renderLabel = (_query) => 'Visit duration'
return new Metric({
width: 'w-28 md:w-24',
...props,
key: 'visit_duration',
renderLabel,
sortable: true
})
}
export const createBounceRate = (props) => {
const renderLabel = (_query) => 'Bounce rate'
return new Metric({
width: 'w-28 md:w-24',
...props,
key: 'bounce_rate',
renderLabel,
sortable: true
})
}
export const createPageviews = (props) => {
const renderLabel = (_query) => 'Pageviews'
return new Metric({
width: 'w-28',
...props,
key: 'pageviews',
renderLabel,
sortable: true
})
}
export const createTimeOnPage = (props) => {
const renderLabel = (_query) => 'Time on page'
return new Metric({
width: 'w-28 md:w-24',
...props,
key: 'time_on_page',
renderLabel,
sortable: true
})
}
export const createExitRate = (props) => {
const renderLabel = (_query) => 'Exit rate'
return new Metric({
width: 'w-28 md:w-24',
...props,
key: 'exit_rate',
renderLabel,
sortable: true
})
}
export const createScrollDepth = (props) => {
const renderLabel = (_query) => 'Scroll depth'
return new Metric({
width: 'w-28 md:w-24',
...props,
key: 'scroll_depth',
renderLabel,
sortable: true
})
}