diff --git a/public/intl/messages/en-US.json b/public/intl/messages/en-US.json index d455978f5..e68c428a5 100644 --- a/public/intl/messages/en-US.json +++ b/public/intl/messages/en-US.json @@ -332,6 +332,8 @@ "unique": "Unique", "unique-events": "Unique events", "unique-visitors": "Unique visitors", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unique Customers", "unknown": "Unknown", "untitled": "Untitled", diff --git a/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx index abf06aead..c45d0b8b4 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx @@ -44,7 +44,7 @@ export function Revenue({ websiteId, startDate, endDate, unit }: RevenueProps) { const metrics = useMemo(() => { if (!data) return []; - const { sum, count, average, unique_count, comparison } = data.total; + const { sum, count, average, unique_count, arpu, comparison } = data.total; return [ { @@ -55,10 +55,16 @@ export function Revenue({ websiteId, startDate, endDate, unit }: RevenueProps) { }, { value: average, - label: t(labels.average), + label: t(labels.aov), change: comparison ? average - comparison.average : 0, formatValue: (n: number) => formatLongCurrency(n, currency), }, + { + value: arpu, + label: t(labels.arpu), + change: comparison ? arpu - (comparison.arpu ?? 0) : 0, + formatValue: (n: number) => formatLongCurrency(n, currency), + }, { value: count, label: t(labels.transactions), diff --git a/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenueTable.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenueTable.tsx deleted file mode 100644 index f8164147f..000000000 --- a/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenueTable.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { DataColumn, DataTable } from '@umami/react-zen'; -import { useMessages } from '@/components/hooks'; -import { formatLongCurrency } from '@/lib/format'; - -export function RevenueTable({ data = [] }) { - const { t, labels } = useMessages(); - - return ( - - - - {(row: any) => formatLongCurrency(row.sum, row.currency)} - - - {(row: any) => formatLongCurrency(row.count ? row.sum / row.count : 0, row.currency)} - - - - - ); -} diff --git a/src/components/messages.ts b/src/components/messages.ts index 9b403b43b..da1c81aac 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -255,6 +255,8 @@ export const labels: Record = { myAccount: 'label.my-account', transfer: 'label.transfer', transactions: 'label.transactions', + aov: 'label.aov', + arpu: 'label.arpu', uniqueCustomers: 'label.uniqueCustomers', viewedPage: 'message.viewed-page', collectedData: 'message.collected-data', diff --git a/src/queries/sql/reports/getRevenueStats.ts b/src/queries/sql/reports/getRevenueStats.ts index c0eac90fe..116166133 100644 --- a/src/queries/sql/reports/getRevenueStats.ts +++ b/src/queries/sql/reports/getRevenueStats.ts @@ -9,6 +9,7 @@ export interface RevenueStatsResult { count: number; average: number; unique_count: number; + arpu: number; } export async function getRevenueStats( @@ -52,7 +53,11 @@ async function relationalQuery( select sum(revenue.revenue) as sum, count(distinct revenue.event_id) as count, - count(distinct revenue.session_id) as unique_count + count(distinct revenue.session_id) as unique_count, + (select count(distinct session_id) + from website_event + where website_id = {{websiteId::uuid}} + and created_at between {{startDate}} and {{endDate}}) as total_sessions from revenue ${joinQuery} ${cohortQuery} @@ -66,6 +71,7 @@ async function relationalQuery( ).then(result => result?.[0]); total.average = total.count > 0 ? Number(total.sum) / Number(total.count) : 0; + total.arpu = total.total_sessions > 0 ? Number(total.sum) / Number(total.total_sessions) : 0; return total; } @@ -97,12 +103,21 @@ async function clickhouseQuery( and website_event.event_id = website_revenue.event_id` : ''; - const total = await rawQuery<{ sum: number; count: number; unique_count: number }>( + const total = await rawQuery<{ + sum: number; + count: number; + unique_count: number; + total_sessions: number; + }>( ` select sum(website_revenue.revenue) as sum, uniqExact(website_revenue.event_id) as count, - uniqExact(website_revenue.session_id) as unique_count + uniqExact(website_revenue.session_id) as unique_count, + (select uniqExact(session_id) + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64}) as total_sessions from website_revenue ${joinQuery} ${cohortQuery} @@ -115,6 +130,7 @@ async function clickhouseQuery( ).then(result => result?.[0]); total.average = total.count > 0 ? total.sum / total.count : 0; + total.arpu = total.total_sessions > 0 ? total.sum / total.total_sessions : 0; return total; }