From 99a328359b6c3c600e484ba211bed0ae103272e2 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 17 Feb 2026 22:14:10 -0800 Subject: [PATCH] add comparison to events page metric bar --- .../[websiteId]/events/EventsPage.tsx | 75 +++++++++++-------- .../[websiteId]/events/stats/route.ts | 15 +++- .../hooks/queries/useEventStatsQuery.ts | 6 ++ 3 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx b/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx index dc46fe41e..5f5ab82a8 100644 --- a/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx @@ -1,12 +1,11 @@ 'use client'; import { Column, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen'; -import locale from 'date-fns/locale/af'; -import { type Key, useMemo, useState } from 'react'; +import { type Key, useState } from 'react'; import { SessionModal } from '@/app/(main)/websites/[websiteId]/sessions/SessionModal'; import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls'; import { LoadingPanel } from '@/components/common/LoadingPanel'; import { Panel } from '@/components/common/Panel'; -import { useMessages } from '@/components/hooks'; +import { useDateRange, useMessages } from '@/components/hooks'; import { useEventStatsQuery } from '@/components/hooks/queries/useEventStatsQuery'; import { EventsChart } from '@/components/metrics/EventsChart'; import { MetricCard } from '@/components/metrics/MetricCard'; @@ -21,6 +20,7 @@ const KEY_NAME = 'umami.events.tab'; export function EventsPage({ websiteId }) { const [tab, setTab] = useState(getItem(KEY_NAME) || 'chart'); + const { isAllTime } = useDateRange(); const { t, labels, getErrorMessage } = useMessages(); const { data, isLoading, isFetching, error } = useEventStatsQuery({ websiteId, @@ -31,34 +31,36 @@ export function EventsPage({ websiteId }) { setTab(value); }; - const metrics = useMemo(() => { - if (!data) return []; + const { events, visitors, visits, uniqueEvents, comparison } = data || {}; - const { events, visitors, visits, uniqueEvents } = data || {}; - - return [ - { - value: visitors, - label: t(labels.visitors), - formatValue: formatLongNumber, - }, - { - value: visits, - label: t(labels.visits), - formatValue: formatLongNumber, - }, - { - value: events, - label: t(labels.events), - formatValue: formatLongNumber, - }, - { - value: uniqueEvents, - label: t(labels.uniqueEvents), - formatValue: formatLongNumber, - }, - ] as any; - }, [data, locale]); + const metrics = data + ? [ + { + value: visitors, + label: t(labels.visitors), + change: visitors - comparison.visitors, + formatValue: formatLongNumber, + }, + { + value: visits, + label: t(labels.visits), + change: visits - comparison.visits, + formatValue: formatLongNumber, + }, + { + value: events, + label: t(labels.events), + change: events - comparison.events, + formatValue: formatLongNumber, + }, + { + value: uniqueEvents, + label: t(labels.uniqueEvents), + change: uniqueEvents - comparison.uniqueEvents, + formatValue: formatLongNumber, + }, + ] + : null; return ( @@ -71,8 +73,17 @@ export function EventsPage({ websiteId }) { minHeight="136px" > - {metrics?.map(({ label, value, formatValue }) => { - return ; + {metrics?.map(({ label, value, change, formatValue }) => { + return ( + + ); })} diff --git a/src/app/api/websites/[websiteId]/events/stats/route.ts b/src/app/api/websites/[websiteId]/events/stats/route.ts index 6d0a04602..fceb97cbd 100644 --- a/src/app/api/websites/[websiteId]/events/stats/route.ts +++ b/src/app/api/websites/[websiteId]/events/stats/route.ts @@ -1,3 +1,4 @@ +import { getCompareDate } from '@/lib/date'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams, withDateRange } from '@/lib/schema'; @@ -28,5 +29,17 @@ export async function GET( const data = await getWebsiteEventStats(websiteId, filters); - return json({ data }); + const { startDate, endDate } = getCompareDate( + filters.compare ?? 'prev', + filters.startDate, + filters.endDate, + ); + + const comparison = await getWebsiteEventStats(websiteId, { + ...filters, + startDate, + endDate, + }); + + return json({ data: { ...data, comparison } }); } diff --git a/src/components/hooks/queries/useEventStatsQuery.ts b/src/components/hooks/queries/useEventStatsQuery.ts index 44316ca5f..b3ca60eaa 100644 --- a/src/components/hooks/queries/useEventStatsQuery.ts +++ b/src/components/hooks/queries/useEventStatsQuery.ts @@ -8,6 +8,12 @@ export interface EventStatsData { visitors: number; visits: number; uniqueEvents: number; + comparison: { + events: number; + visitors: number; + visits: number; + uniqueEvents: number; + }; } type EventStatsApiResponse = {