import { useOverviewOptions } from '@/components/overview/useOverviewOptions'; import { useEventQueryFilters } from '@/hooks/use-event-query-filters'; import { cn } from '@/utils/cn'; import { useDashedStroke } from '@/hooks/use-dashed-stroke'; import { useFormatDateInterval } from '@/hooks/use-format-date-interval'; import { useNumber } from '@/hooks/use-numer-formatter'; import { useTRPC } from '@/integrations/trpc/react'; import type { RouterOutputs } from '@/trpc/client'; import { getChartColor } from '@/utils/theme'; import { getPreviousMetric } from '@openpanel/common'; import type { IInterval } from '@openpanel/validation'; import { useQuery } from '@tanstack/react-query'; import { isSameDay, isSameHour, isSameMonth, isSameWeek } from 'date-fns'; import { last, omit } from 'ramda'; import React, { useState } from 'react'; import { Bar, CartesianGrid, ComposedChart, Line, ResponsiveContainer, XAxis, YAxis, } from 'recharts'; import { createChartTooltip } from '../charts/chart-tooltip'; import { BarShapeBlue } from '../charts/common-bar'; import { useXAxisProps, useYAxisProps } from '../report-chart/common/axis'; import { PreviousDiffIndicatorPure } from '../report-chart/common/previous-diff-indicator'; import { Skeleton } from '../skeleton'; import { OverviewLiveHistogram } from './overview-live-histogram'; import { OverviewMetricCard } from './overview-metric-card'; interface OverviewMetricsProps { projectId: string; } const TITLES = [ { title: 'Unique Visitors', key: 'unique_visitors', unit: '', inverted: false, }, { title: 'Sessions', key: 'total_sessions', unit: '', inverted: false, }, { title: 'Pageviews', key: 'total_screen_views', unit: '', inverted: false, }, { title: 'Pages per session', key: 'views_per_session', unit: '', inverted: false, }, { title: 'Bounce Rate', key: 'bounce_rate', unit: '%', inverted: true, }, { title: 'Session Duration', key: 'avg_session_duration', unit: 'min', inverted: false, }, ] as const; export default function OverviewMetrics({ projectId }: OverviewMetricsProps) { const { range, interval, metric, setMetric, startDate, endDate } = useOverviewOptions(); const [filters] = useEventQueryFilters(); const trpc = useTRPC(); const activeMetric = TITLES[metric]!; const overviewQuery = useQuery( trpc.overview.stats.queryOptions({ projectId, range, interval, filters, startDate, endDate, }), ); const data = overviewQuery.data?.series?.map((item) => ({ ...item, timestamp: new Date(item.date).getTime(), })) || []; return ( <>
{TITLES.map((title, index) => ( setMetric(index)} label={title.title} metric={{ current: overviewQuery.data?.metrics[title.key] ?? 0, previous: overviewQuery.data?.metrics[`prev_${title.key}`], }} unit={title.unit} data={data.map((item) => ({ current: item[title.key], previous: item[`prev_${title.key}`], }))} active={metric === index} isLoading={overviewQuery.isLoading} /> ))}
{activeMetric.title}
{overviewQuery.isLoading && }
); } const { Tooltip, TooltipProvider } = createChartTooltip< RouterOutputs['overview']['stats']['series'][number], { metric: (typeof TITLES)[number]; interval: IInterval; } >(({ context: { metric, interval }, data: dataArray }) => { const data = dataArray[0]; const formatDate = useFormatDateInterval(interval); const number = useNumber(); if (!data) { return null; } return ( <>
{formatDate(new Date(data.date))}
{metric.title}
{number.formatWithUnit(data[metric.key])} {!!data[`prev_${metric.key}`] && ( ({number.formatWithUnit(data[`prev_${metric.key}`])}) )}
); }); function Chart({ activeMetric, interval, data, }: { activeMetric: (typeof TITLES)[number]; interval: IInterval; data: RouterOutputs['overview']['stats']['series']; }) { const xAxisProps = useXAxisProps({ interval }); const yAxisProps = useYAxisProps(); const [activeBar, setActiveBar] = useState(-1); return ( { setActiveBar(e.activeTooltipIndex ?? -1); }} barCategoryGap={2} > ( )} /> ); }