import React from 'react' import { Tooltip } from '../../util/tooltip' import { SecondsSinceLastLoad } from '../../util/seconds-since-last-load' import classNames from 'classnames' import * as storage from '../../util/storage' import { formatDateRange } from '../../util/date' import { useQueryContext } from '../../query-context' import { useSiteContext } from '../../site-context' import { useLastLoadContext } from '../../last-load-context' import { ChangeArrow } from '../reports/change-arrow' import { MetricFormatterShort, MetricFormatterLong } from '../reports/metric-formatter' function topStatNumberShort(metric, value) { const formatter = MetricFormatterShort[metric] return formatter(value) } function topStatNumberLong(metric, value) { const formatter = MetricFormatterLong[metric] return formatter(value) } export default function TopStats({ data, onMetricUpdate, tooltipBoundary, graphableMetrics }) { const { query } = useQueryContext() const lastLoadTimestamp = useLastLoadContext() const site = useSiteContext() const isComparison = query.comparison && data && data.comparing_from function tooltip(stat) { let statName = stat.name.toLowerCase() const warning = warningText(stat.graph_metric, site) statName = stat.value === 1 ? statName.slice(0, -1) : statName return (
{isComparison && (
{topStatNumberLong(stat.graph_metric, stat.value)} vs.{' '} {topStatNumberLong(stat.graph_metric, stat.comparison_value)}{' '} {statName}
)} {!isComparison && (
{topStatNumberLong(stat.graph_metric, stat.value)} {statName}
)} {stat.name === 'Current visitors' && (

Last updated{' '} s ago

)} {warning ? (

* {warning}

) : null}
) } function warningText(metric) { const warning = data.meta.metric_warnings?.[metric] if (!warning) { return null } if ( metric === 'scroll_depth' && warning.code === 'no_imported_scroll_depth' ) { return 'Does not include imported data' } if (metric === 'time_on_page') { return warning.message } return null } function canMetricBeGraphed(stat) { return graphableMetrics.includes(stat.graph_metric) } function maybeUpdateMetric(stat) { if (canMetricBeGraphed(stat)) { storage.setItem(`metric__${site.domain}`, stat.graph_metric) onMetricUpdate(stat.graph_metric) } } function blinkingDot() { return (
) } function getStoredMetric() { return storage.getItem(`metric__${site.domain}`) } function renderStatName(stat) { const isSelected = stat.graph_metric === getStoredMetric() const [statDisplayName, statExtraName] = stat.name.split(/(\(.+\))/g) const statDisplayNameClass = classNames( 'text-xs font-bold tracking-wide text-gray-500 uppercase dark:text-gray-400 whitespace-nowrap flex w-fit border-b', { 'text-indigo-600 dark:text-indigo-500 border-indigo-600 dark:border-indigo-500': isSelected, 'group-hover:text-indigo-700 dark:group-hover:text-indigo-500 border-transparent': !isSelected } ) return (
{statDisplayName} {statExtraName && ( {statExtraName} )} {warningText(stat.graph_metric) && ( * )}
) } function renderStat(stat, index) { const className = classNames( 'px-4 md:px-6 w-1/2 my-4 lg:w-auto group select-none', { 'cursor-pointer': canMetricBeGraphed(stat), 'lg:border-l border-gray-300 dark:border-gray-700': index > 0, 'border-r lg:border-r-0': index % 2 === 0 } ) return ( { maybeUpdateMetric(stat) }} boundary={tooltipBoundary} > {renderStatName(stat)}

{topStatNumberShort(stat.graph_metric, stat.value)}

{!isComparison && stat.change != null ? ( ) : null}
{isComparison ? (

{formatDateRange(site, data.from, data.to)}

) : null}
{isComparison ? (

{topStatNumberShort(stat.graph_metric, stat.comparison_value)}

{formatDateRange(site, data.comparing_from, data.comparing_to)}

) : null}
) } const stats = data && data.top_stats.filter((stat) => stat.value !== null).map(renderStat) if (stats && query.period === 'realtime') { stats.push(blinkingDot()) } return stats || null }