-
+
+
+
+ {item => - {item}
}
+
-
+
{formatMessage(labels.runQuery)}
diff --git a/src/app/(main)/reports/revenue/RevenueReport.module.css b/src/app/(main)/reports/revenue/RevenueReport.module.css
deleted file mode 100644
index aed66b74..00000000
--- a/src/app/(main)/reports/revenue/RevenueReport.module.css
+++ /dev/null
@@ -1,10 +0,0 @@
-.filters {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- border: 1px solid var(--base400);
- border-radius: var(--border-radius);
- line-height: 32px;
- padding: 10px;
- overflow: hidden;
-}
diff --git a/src/app/(main)/reports/revenue/RevenueReport.tsx b/src/app/(main)/reports/revenue/RevenueReport.tsx
index d67f57c0..7b75ebd2 100644
--- a/src/app/(main)/reports/revenue/RevenueReport.tsx
+++ b/src/app/(main)/reports/revenue/RevenueReport.tsx
@@ -1,15 +1,15 @@
-import RevenueChart from './RevenueChart';
-import RevenueParameters from './RevenueParameters';
-import Report from '../[reportId]/Report';
-import ReportHeader from '../[reportId]/ReportHeader';
-import ReportMenu from '../[reportId]/ReportMenu';
-import ReportBody from '../[reportId]/ReportBody';
import Money from 'assets/money.svg';
import { REPORT_TYPES } from 'lib/constants';
+import Report from '../[reportId]/Report';
+import ReportBody from '../[reportId]/ReportBody';
+import ReportHeader from '../[reportId]/ReportHeader';
+import ReportMenu from '../[reportId]/ReportMenu';
+import RevenueParameters from './RevenueParameters';
+import RevenueView from './RevenueView';
const defaultParameters = {
type: REPORT_TYPES.revenue,
- parameters: { Revenue: [] },
+ parameters: {},
};
export default function RevenueReport({ reportId }: { reportId?: string }) {
@@ -20,7 +20,7 @@ export default function RevenueReport({ reportId }: { reportId?: string }) {
-
+
);
diff --git a/src/app/(main)/reports/revenue/RevenueTable.tsx b/src/app/(main)/reports/revenue/RevenueTable.tsx
new file mode 100644
index 00000000..f038aed9
--- /dev/null
+++ b/src/app/(main)/reports/revenue/RevenueTable.tsx
@@ -0,0 +1,38 @@
+import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
+import { useMessages } from 'components/hooks';
+import { useContext } from 'react';
+import { GridColumn, GridTable } from 'react-basics';
+import { ReportContext } from '../[reportId]/Report';
+import { formatLongCurrency } from 'lib/format';
+
+export function RevenueTable() {
+ const { report } = useContext(ReportContext);
+ const { formatMessage, labels } = useMessages();
+ const { data } = report || {};
+
+ if (!data) {
+ return ;
+ }
+
+ return (
+
+
+ {row => row.currency}
+
+
+ {row => formatLongCurrency(row.sum, row.currency)}
+
+
+ {row => formatLongCurrency(row.avg, row.currency)}
+
+
+ {row => row.count}
+
+
+ {row => row.uniqueCount}
+
+
+ );
+}
+
+export default RevenueTable;
diff --git a/src/app/(main)/reports/revenue/RevenueView.module.css b/src/app/(main)/reports/revenue/RevenueView.module.css
new file mode 100644
index 00000000..d9b10548
--- /dev/null
+++ b/src/app/(main)/reports/revenue/RevenueView.module.css
@@ -0,0 +1,5 @@
+.container {
+ display: grid;
+ gap: 20px;
+ margin-bottom: 40px;
+}
diff --git a/src/app/(main)/reports/revenue/RevenueView.tsx b/src/app/(main)/reports/revenue/RevenueView.tsx
new file mode 100644
index 00000000..fa62778e
--- /dev/null
+++ b/src/app/(main)/reports/revenue/RevenueView.tsx
@@ -0,0 +1,140 @@
+import { colord } from 'colord';
+import BarChart from 'components/charts/BarChart';
+import PieChart from 'components/charts/PieChart';
+import { useLocale, useMessages } from 'components/hooks';
+import { GridRow } from 'components/layout/Grid';
+import ListTable from 'components/metrics/ListTable';
+import MetricCard from 'components/metrics/MetricCard';
+import MetricsBar from 'components/metrics/MetricsBar';
+import { renderDateLabels } from 'lib/charts';
+import { CHART_COLORS } from 'lib/constants';
+import { formatLongCurrency, formatLongNumber } from 'lib/format';
+import { useContext, useMemo } from 'react';
+import { ReportContext } from '../[reportId]/Report';
+import RevenueTable from './RevenueTable';
+import styles from './RevenueView.module.css';
+
+export interface RevenueViewProps {
+ isLoading?: boolean;
+}
+
+export function RevenueView({ isLoading }: RevenueViewProps) {
+ const { formatMessage, labels } = useMessages();
+ const { locale } = useLocale();
+ const { report } = useContext(ReportContext);
+ const {
+ data,
+ parameters: { dateRange, currency },
+ } = report || {};
+ const showTable = data?.table.length > 1;
+
+ const chartData = useMemo(() => {
+ if (!data) return [];
+
+ const map = (data.chart as any[]).reduce((obj, { x, t, y }) => {
+ if (!obj[x]) {
+ obj[x] = [];
+ }
+
+ obj[x].push({ x: t, y });
+
+ return obj;
+ }, {});
+
+ return {
+ datasets: Object.keys(map).map((key, index) => {
+ const color = colord(CHART_COLORS[index % CHART_COLORS.length]);
+ return {
+ label: key,
+ data: map[key],
+ lineTension: 0,
+ backgroundColor: color.alpha(0.6).toRgbString(),
+ borderColor: color.alpha(0.7).toRgbString(),
+ borderWidth: 1,
+ };
+ }),
+ };
+ }, [data]);
+
+ const countryData = useMemo(() => {
+ if (!data) return [];
+
+ const labels = data.country.map(({ name }) => name);
+ const datasets = [
+ {
+ data: data.country.map(({ value }) => value),
+ backgroundColor: CHART_COLORS,
+ borderWidth: 0,
+ },
+ ];
+
+ return { labels, datasets };
+ }, [data]);
+
+ const metricData = useMemo(() => {
+ if (!data) return [];
+
+ const { sum, avg, count, uniqueCount } = data.total;
+
+ return [
+ {
+ value: sum,
+ label: formatMessage(labels.total),
+ formatValue: n => formatLongCurrency(n, currency),
+ },
+ {
+ value: avg,
+ label: formatMessage(labels.average),
+ formatValue: n => formatLongCurrency(n, currency),
+ },
+ {
+ value: count,
+ label: formatMessage(labels.transactions),
+ formatValue: formatLongNumber,
+ },
+ {
+ value: uniqueCount,
+ label: formatMessage(labels.uniqueCustomers),
+ formatValue: formatLongNumber,
+ },
+ ] as any;
+ }, [data, locale]);
+
+ return (
+ <>
+
+
+ {metricData?.map(({ label, value, formatValue }) => {
+ return ;
+ })}
+
+
+ {data && (
+
+ ({
+ x: name,
+ y: value,
+ z: (value / data?.total.sum) * 100,
+ }))}
+ />
+
+
+ )}
+ {showTable &&
}
+
+ >
+ );
+}
+
+export default RevenueView;
diff --git a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
index 794a5053..760f34f9 100644
--- a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
+++ b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
@@ -54,7 +54,7 @@ export function EventProperties({ websiteId }: { websiteId: string }) {
{propertyName && (
)}
diff --git a/src/components/charts/BarChart.tsx b/src/components/charts/BarChart.tsx
index 7624ba1c..eadc4af7 100644
--- a/src/components/charts/BarChart.tsx
+++ b/src/components/charts/BarChart.tsx
@@ -7,6 +7,7 @@ import { useMemo, useState } from 'react';
export interface BarChartProps extends ChartProps {
unit: string;
stacked?: boolean;
+ currency?: string;
renderXLabel?: (label: string, index: number, values: any[]) => string;
renderYLabel?: (label: string, index: number, values: any[]) => string;
XAxisType?: string;
@@ -27,6 +28,7 @@ export function BarChart(props: BarChartProps) {
stacked = false,
minDate,
maxDate,
+ currency,
} = props;
const options: any = useMemo(() => {
@@ -76,7 +78,9 @@ export function BarChart(props: BarChartProps) {
const handleTooltip = ({ tooltip }: { tooltip: any }) => {
const { opacity } = tooltip;
- setTooltip(opacity ? : null);
+ setTooltip(
+ opacity ? : null,
+ );
};
return (
diff --git a/src/components/charts/BarChartTooltip.tsx b/src/components/charts/BarChartTooltip.tsx
index fed5af92..201c6e4c 100644
--- a/src/components/charts/BarChartTooltip.tsx
+++ b/src/components/charts/BarChartTooltip.tsx
@@ -1,7 +1,7 @@
-import { formatDate } from 'lib/date';
-import { Flexbox, StatusLight } from 'react-basics';
-import { formatLongNumber } from 'lib/format';
import { useLocale } from 'components/hooks';
+import { formatDate } from 'lib/date';
+import { formatLongCurrency, formatLongNumber } from 'lib/format';
+import { Flexbox, StatusLight } from 'react-basics';
const formats = {
millisecond: 'T',
@@ -15,7 +15,7 @@ const formats = {
year: 'yyyy',
};
-export default function BarChartTooltip({ tooltip, unit }) {
+export default function BarChartTooltip({ tooltip, unit, currency }) {
const { locale } = useLocale();
const { labelColors, dataPoints } = tooltip;
@@ -26,7 +26,10 @@ export default function BarChartTooltip({ tooltip, unit }) {
- {formatLongNumber(dataPoints[0].raw.y)} {dataPoints[0].dataset.label}
+ {currency
+ ? formatLongCurrency(dataPoints[0].raw.y, currency)
+ : formatLongNumber(dataPoints[0].raw.y)}{' '}
+ {dataPoints[0].dataset.label}
diff --git a/src/components/hooks/queries/useEventDataValues.ts b/src/components/hooks/queries/useEventDataValues.ts
index 9960b3db..de6783a0 100644
--- a/src/components/hooks/queries/useEventDataValues.ts
+++ b/src/components/hooks/queries/useEventDataValues.ts
@@ -12,7 +12,7 @@ export function useEventDataValues(
const params = useFilterParams(websiteId);
return useQuery({
- queryKey: ['websites:event-data:values', { websiteId, propertyName, ...params }],
+ queryKey: ['websites:event-data:values', { websiteId, eventName, propertyName, ...params }],
queryFn: () =>
get(`/websites/${websiteId}/event-data/values`, { ...params, eventName, propertyName }),
enabled: !!(websiteId && propertyName),
diff --git a/src/components/messages.ts b/src/components/messages.ts
index 933a7a0f..1d2cc9b2 100644
--- a/src/components/messages.ts
+++ b/src/components/messages.ts
@@ -114,8 +114,6 @@ export const labels = defineMessages({
none: { id: 'label.none', defaultMessage: 'None' },
clearAll: { id: 'label.clear-all', defaultMessage: 'Clear all' },
property: { id: 'label.property', defaultMessage: 'Property' },
- revenueProperty: { id: 'label.revenue-property', defaultMessage: 'Revenue Property' },
- userProperty: { id: 'label.user-property', defaultMessage: 'User Property' },
today: { id: 'label.today', defaultMessage: 'Today' },
lastHours: { id: 'label.last-hours', defaultMessage: 'Last {x} hours' },
yesterday: { id: 'label.yesterday', defaultMessage: 'Yesterday' },
@@ -162,8 +160,9 @@ export const labels = defineMessages({
revenue: { id: 'label.revenue', defaultMessage: 'Revenue' },
revenueDescription: {
id: 'label.revenue-description',
- defaultMessage: 'Look into your revenue across time.',
+ defaultMessage: 'Look into your revenue data and how users are spending.',
},
+ currency: { id: 'label.currency', defaultMessage: 'Currency' },
url: { id: 'label.url', defaultMessage: 'URL' },
urls: { id: 'label.urls', defaultMessage: 'URLs' },
path: { id: 'label.path', defaultMessage: 'Path' },
diff --git a/src/lib/format.ts b/src/lib/format.ts
index a662a9eb..ba3243f7 100644
--- a/src/lib/format.ts
+++ b/src/lib/format.ts
@@ -47,6 +47,9 @@ export function formatNumber(n: string | number) {
export function formatLongNumber(value: number) {
const n = Number(value);
+ if (n >= 1000000000) {
+ return `${(n / 1000000).toFixed(1)}b`;
+ }
if (n >= 1000000) {
return `${(n / 1000000).toFixed(1)}m`;
}
@@ -78,3 +81,26 @@ export function stringToColor(str: string) {
}
return color;
}
+
+export function formatCurrency(value: number, currency: string, locale = 'en-US') {
+ return new Intl.NumberFormat(locale, {
+ style: 'currency',
+ currency: currency,
+ }).format(value);
+}
+
+export function formatLongCurrency(value: number, currency: string, locale = 'en-US') {
+ const n = Number(value);
+
+ if (n >= 1000000000) {
+ return `${formatCurrency(n / 1000000000, currency, locale)}b`;
+ }
+ if (n >= 1000000) {
+ return `${formatCurrency(n / 1000000, currency, locale)}m`;
+ }
+ if (n >= 1000) {
+ return `${formatCurrency(n / 1000, currency, locale)}k`;
+ }
+
+ return formatCurrency(n / 1000, currency, locale);
+}
diff --git a/src/pages/api/reports/revenue.ts b/src/pages/api/reports/revenue.ts
index ac4dc6b3..39014d25 100644
--- a/src/pages/api/reports/revenue.ts
+++ b/src/pages/api/reports/revenue.ts
@@ -7,34 +7,30 @@ import { methodNotAllowed, ok, unauthorized } from 'next-basics';
import { getRevenue } from 'queries/analytics/reports/getRevenue';
import * as yup from 'yup';
-export interface RetentionRequestBody {
+export interface RevenueRequestBody {
websiteId: string;
- dateRange: { startDate: string; endDate: string; unit?: string; timezone?: string };
- eventName: string;
- revenueProperty: string;
- userProperty: string;
+ currency: string;
+ timezone: string;
+ dateRange: { startDate: string; endDate: string; unit?: string };
}
const schema = {
POST: yup.object().shape({
websiteId: yup.string().uuid().required(),
+ timezone: TimezoneTest,
dateRange: yup
.object()
.shape({
startDate: yup.date().required(),
endDate: yup.date().required(),
unit: UnitTypeTest,
- timezone: TimezoneTest,
})
.required(),
- eventName: yup.string().required(),
- revenueProperty: yup.string().required(),
- userProperty: yup.string(),
}),
};
export default async (
- req: NextApiRequestQueryBody,
+ req: NextApiRequestQueryBody,
res: NextApiResponse,
) => {
await useCors(req, res);
@@ -44,10 +40,9 @@ export default async (
if (req.method === 'POST') {
const {
websiteId,
- dateRange: { startDate, endDate, unit, timezone },
- eventName,
- revenueProperty,
- userProperty,
+ currency,
+ timezone,
+ dateRange: { startDate, endDate, unit },
} = req.body;
if (!(await canViewWebsite(req.auth, websiteId))) {
@@ -59,9 +54,7 @@ export default async (
endDate: new Date(endDate),
unit,
timezone,
- eventName,
- revenueProperty,
- userProperty,
+ currency,
});
return ok(res, data);
diff --git a/src/queries/analytics/reports/getRevenue.ts b/src/queries/analytics/reports/getRevenue.ts
index 502505f4..9d9a4a14 100644
--- a/src/queries/analytics/reports/getRevenue.ts
+++ b/src/queries/analytics/reports/getRevenue.ts
@@ -10,9 +10,7 @@ export async function getRevenue(
endDate: Date;
unit: string;
timezone: string;
- eventName: string;
- revenueProperty: string;
- userProperty: string;
+ currency: string;
},
]
) {
@@ -29,23 +27,12 @@ async function relationalQuery(
endDate: Date;
unit: string;
timezone: string;
- eventName: string;
- revenueProperty: string;
- userProperty: string;
},
): Promise<{
chart: { time: string; sum: number; avg: number; count: number; uniqueCount: number }[];
total: { sum: number; avg: number; count: number; uniqueCount: number };
}> {
- const {
- startDate,
- endDate,
- eventName,
- revenueProperty,
- userProperty,
- timezone = 'UTC',
- unit = 'day',
- } = criteria;
+ const { startDate, endDate, timezone = 'UTC', unit = 'day' } = criteria;
const { getDateSQL, rawQuery } = prisma;
const chartRes = await rawQuery(
@@ -63,7 +50,7 @@ async function relationalQuery(
and data_key in ({{revenueProperty}} , {{userProperty}})
group by 1
`,
- { websiteId, startDate, endDate, eventName, revenueProperty, userProperty },
+ { websiteId, startDate, endDate },
);
const totalRes = await rawQuery(
@@ -80,7 +67,7 @@ async function relationalQuery(
and data_key in ({{revenueProperty}} , {{userProperty}})
group by 1
`,
- { websiteId, startDate, endDate, eventName, revenueProperty, userProperty },
+ { websiteId, startDate, endDate },
);
return { chart: chartRes, total: totalRes };
@@ -91,59 +78,81 @@ async function clickhouseQuery(
criteria: {
startDate: Date;
endDate: Date;
- eventName: string;
- revenueProperty: string;
- userProperty: string;
unit: string;
timezone: string;
+ currency: string;
},
): Promise<{
- chart: { time: string; sum: number; avg: number; count: number; uniqueCount: number }[];
+ chart: { x: string; t: string; y: number }[];
+ country: { name: string; value: number }[];
total: { sum: number; avg: number; count: number; uniqueCount: number };
-}> {
- const {
- startDate,
- endDate,
- eventName,
- revenueProperty,
- userProperty = '',
- timezone = 'UTC',
- unit = 'day',
- } = criteria;
- const { getDateStringSQL, getDateSQL, rawQuery } = clickhouse;
-
- const chartRes = await rawQuery<{
- time: string;
+ table: {
+ currency: string;
sum: number;
avg: number;
count: number;
uniqueCount: number;
- }>(
+ }[];
+}> {
+ const { startDate, endDate, timezone = 'UTC', unit = 'day', currency } = criteria;
+ const { getDateSQL, rawQuery } = clickhouse;
+
+ const chartRes = await rawQuery<
+ {
+ x: string;
+ t: string;
+ y: number;
+ }[]
+ >(
`
select
- ${getDateStringSQL('g.time', unit)} as time,
- g.sum as sum,
- g.avg as avg,
- g.count as count,
- g.uniqueCount as uniqueCount
- from (
- select
- ${getDateSQL('created_at', unit, timezone)} as time,
- sumIf(number_value, data_key = {revenueProperty:String}) as sum,
- avgIf(number_value, data_key = {revenueProperty:String}) as avg,
- countIf(data_key = {revenueProperty:String}) as count,
- uniqExactIf(string_value, data_key = {userProperty:String}) as uniqueCount
- from event_data
- where website_id = {websiteId:UUID}
- and created_at between {startDate:DateTime64} and {endDate:DateTime64}
- and event_name = {eventName:String}
- and data_key in ({revenueProperty:String}, {userProperty:String})
- group by time
- ) as g
- order by time
+ event_name x,
+ ${getDateSQL('created_at', unit, timezone)} t,
+ sum(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) y
+ from event_data
+ join (select event_id
+ from event_data
+ where positionCaseInsensitive(data_key, 'currency') > 0
+ and string_value = {currency:String}) currency
+ on currency.event_id = event_data.event_id
+ where website_id = {websiteId:UUID}
+ and created_at between {startDate:DateTime64} and {endDate:DateTime64}
+ and positionCaseInsensitive(data_key, 'revenue') > 0
+ group by x, t
+ order by t
`,
- { websiteId, startDate, endDate, eventName, revenueProperty, userProperty },
- ).then(result => result?.[0]);
+ { websiteId, startDate, endDate, unit, timezone, currency },
+ );
+
+ const countryRes = await rawQuery<
+ {
+ name: string;
+ value: number;
+ }[]
+ >(
+ `
+ select
+ s.country as name,
+ sum(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) as value
+ from event_data ed
+ join (select event_id
+ from event_data
+ where positionCaseInsensitive(data_key, 'currency') > 0
+ and string_value = {currency:String}) c
+ on c.event_id = ed.event_id
+ join (select distinct website_id, session_id, country
+ from website_event_stats_hourly
+ where website_id = {websiteId:UUID}) s
+ on ed.website_id = s.website_id
+ and ed.session_id = s.session_id
+ where ed.website_id = {websiteId:UUID}
+ and ed.created_at between {startDate:DateTime64} and {endDate:DateTime64}
+ and positionCaseInsensitive(ed.data_key, 'revenue') > 0
+ group by s.country
+
+ `,
+ { websiteId, startDate, endDate, currency },
+ );
const totalRes = await rawQuery<{
sum: number;
@@ -152,19 +161,53 @@ async function clickhouseQuery(
uniqueCount: number;
}>(
`
- select
- sumIf(number_value, data_key = {revenueProperty:String}) as sum,
- avgIf(number_value, data_key = {revenueProperty:String}) as avg,
- countIf(data_key = {revenueProperty:String}) as count,
- uniqExactIf(string_value, data_key = {userProperty:String}) as uniqueCount
- from event_data
+ select
+ sum(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) as sum,
+ avg(coalesce(toDecimal64(number_value, 2), toDecimal64(string_value, 2))) as avg,
+ uniqExact(event_id) as count,
+ uniqExact(session_id) as uniqueCount
+ from event_data
+ join (select event_id
+ from event_data
+ where positionCaseInsensitive(data_key, 'currency') > 0
+ and string_value = {currency:String}) currency
+ on currency.event_id = event_data.event_id
where website_id = {websiteId:UUID}
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
- and event_name = {eventName:String}
- and data_key in ({revenueProperty:String}, {userProperty:String})
+ and positionCaseInsensitive(data_key, 'revenue') > 0
`,
- { websiteId, startDate, endDate, eventName, revenueProperty, userProperty },
+ { websiteId, startDate, endDate, currency },
+ ).then(result => result?.[0]);
+
+ const tableRes = await rawQuery<
+ {
+ currency: string;
+ sum: number;
+ avg: number;
+ count: number;
+ uniqueCount: number;
+ }[]
+ >(
+ `
+ select
+ c.currency,
+ sum(coalesce(toDecimal64(ed.number_value, 2), toDecimal64(ed.string_value, 2))) as sum,
+ avg(coalesce(toDecimal64(ed.number_value, 2), toDecimal64(ed.string_value, 2))) as avg,
+ uniqExact(ed.event_id) as count,
+ uniqExact(ed.session_id) as uniqueCount
+ from event_data ed
+ join (select event_id, string_value as currency
+ from event_data
+ where positionCaseInsensitive(data_key, 'currency') > 0) c
+ ON c.event_id = ed.event_id
+ where website_id = {websiteId:UUID}
+ and created_at between {startDate:DateTime64} and {endDate:DateTime64}
+ and positionCaseInsensitive(data_key, 'revenue') > 0
+ group by c.currency
+ order by sum desc;
+ `,
+ { websiteId, startDate, endDate, unit, timezone, currency },
);
- return { chart: chartRes, total: totalRes };
+ return { chart: chartRes, country: countryRes, total: totalRes, table: tableRes };
}
diff --git a/src/queries/analytics/sessions/getWebsiteSession.ts b/src/queries/analytics/sessions/getWebsiteSession.ts
index f9b9f39a..2c16741e 100644
--- a/src/queries/analytics/sessions/getWebsiteSession.ts
+++ b/src/queries/analytics/sessions/getWebsiteSession.ts
@@ -47,7 +47,7 @@ async function relationalQuery(websiteId: string, sessionId: string) {
min(website_event.created_at) as min_time,
max(website_event.created_at) as max_time,
sum(case when website_event.event_type = 1 then 1 else 0 end) as views,
- sum(case when website_event.event_type = 1 then 1 else 0 end) as events
+ sum(case when website_event.event_type = 2 then 1 else 0 end) as events
from session
join website_event on website_event.session_id = session.session_id
where session.website_id = {{websiteId::uuid}}
diff --git a/src/queries/analytics/sessions/getWebsiteSessionsWeekly.ts b/src/queries/analytics/sessions/getWebsiteSessionsWeekly.ts
index 153c9bb3..48d4f7a9 100644
--- a/src/queries/analytics/sessions/getWebsiteSessionsWeekly.ts
+++ b/src/queries/analytics/sessions/getWebsiteSessionsWeekly.ts
@@ -34,8 +34,8 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
async function clickhouseQuery(websiteId: string, filters: QueryFilters) {
const { timezone = 'utc' } = filters;
- const { rawQuery } = clickhouse;
- const { startDate, endDate } = filters;
+ const { rawQuery, parseFilters } = clickhouse;
+ const { params } = await parseFilters(websiteId, filters);
return rawQuery(
`
@@ -48,7 +48,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) {
group by time
order by time
`,
- { websiteId, startDate, endDate },
+ params,
).then(formatResults);
}