diff --git a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx index def3f0ba..3b0ad008 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx @@ -7,16 +7,12 @@ import styles from './SessionActivity.module.css'; export function SessionActivity({ websiteId, sessionId, - startDate, - endDate, }: { websiteId: string; sessionId: string; - startDate: string; - endDate: string; }) { const { formatDate } = useTimezone(); - const { data, isLoading } = useSessionActivity(websiteId, sessionId, startDate, endDate); + const { data, isLoading } = useSessionActivity(websiteId, sessionId); if (isLoading) { return ; diff --git a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionDetailsPage.tsx b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionDetailsPage.tsx index d6a07edc..212f8533 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionDetailsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionDetailsPage.tsx @@ -28,12 +28,7 @@ export default function SessionDetailsPage({
- +
diff --git a/src/components/hooks/queries/useSessionActivity.ts b/src/components/hooks/queries/useSessionActivity.ts index 94676a99..e6d7ffa0 100644 --- a/src/components/hooks/queries/useSessionActivity.ts +++ b/src/components/hooks/queries/useSessionActivity.ts @@ -1,17 +1,12 @@ import { useApi } from './useApi'; -export function useSessionActivity( - websiteId: string, - sessionId: string, - startDate: string, - endDate: string, -) { +export function useSessionActivity(websiteId: string, sessionId: string) { const { get, useQuery } = useApi(); return useQuery({ queryKey: ['session:activity', { websiteId, sessionId }], queryFn: () => { - return get(`/websites/${websiteId}/sessions/${sessionId}/activity`, { startDate, endDate }); + return get(`/websites/${websiteId}/sessions/${sessionId}/activity`); }, }); } diff --git a/src/components/hooks/useFilterParams.ts b/src/components/hooks/useFilterParams.ts index 343aea9f..525f3492 100644 --- a/src/components/hooks/useFilterParams.ts +++ b/src/components/hooks/useFilterParams.ts @@ -1,19 +1,18 @@ import { useNavigation } from './useNavigation'; import { useDateRange } from './useDateRange'; import { useTimezone } from './useTimezone'; -import { zonedTimeToUtc } from 'date-fns-tz'; export function useFilterParams(websiteId: string) { const { dateRange } = useDateRange(websiteId); const { startDate, endDate, unit } = dateRange; - const { timezone } = useTimezone(); + const { timezone, toUtc } = useTimezone(); const { query: { url, referrer, title, query, host, os, browser, device, country, region, city, event }, } = useNavigation(); return { - startAt: +zonedTimeToUtc(startDate, timezone), - endAt: +zonedTimeToUtc(endDate, timezone), + startAt: +toUtc(startDate), + endAt: +toUtc(endDate), unit, timezone, url, diff --git a/src/components/hooks/useTimezone.ts b/src/components/hooks/useTimezone.ts index b5e58ea9..24cef02c 100644 --- a/src/components/hooks/useTimezone.ts +++ b/src/components/hooks/useTimezone.ts @@ -1,6 +1,6 @@ import { setItem } from 'next-basics'; import { TIMEZONE_CONFIG } from 'lib/constants'; -import { formatInTimeZone } from 'date-fns-tz'; +import { formatInTimeZone, zonedTimeToUtc, utcToZonedTime } from 'date-fns-tz'; import useStore, { setTimezone } from 'store/app'; const selector = (state: { timezone: string }) => state.timezone; @@ -23,7 +23,15 @@ export function useTimezone() { ); }; - return { timezone, saveTimezone, formatDate }; + const toUtc = (date: Date | string | number) => { + return zonedTimeToUtc(date, timezone); + }; + + const fromUtc = (date: Date | string | number) => { + return utcToZonedTime(date, timezone); + }; + + return { timezone, saveTimezone, formatDate, toUtc, fromUtc }; } export default useTimezone; diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index 78f0323e..63027d75 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -8,6 +8,7 @@ import { filtersToArray } from './params'; import { PageParams, QueryFilters, QueryOptions } from './types'; export const CLICKHOUSE_DATE_FORMATS = { + utc: '%Y-%m-%dT%H:%i:%SZ', second: '%Y-%m-%d %H:%i:%S', minute: '%Y-%m-%d %H:%i:00', hour: '%Y-%m-%d %H:00:00', @@ -47,7 +48,7 @@ function getClient() { return client; } -function getDateStringSQL(data: any, unit: string | number, timezone?: string) { +function getDateStringSQL(data: any, unit: string = 'utc', timezone?: string) { if (timezone) { return `formatDateTime(${data}, '${CLICKHOUSE_DATE_FORMATS[unit]}', '${timezone}')`; } diff --git a/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts b/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts index d1a763fb..8d1b2346 100644 --- a/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts +++ b/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts @@ -9,16 +9,12 @@ import { getSessionActivity } from 'queries'; export interface SessionActivityRequestQuery extends PageParams { websiteId: string; sessionId: string; - startDate: string; - endDate: string; } const schema = { GET: yup.object().shape({ websiteId: yup.string().uuid().required(), sessionId: yup.string().uuid().required(), - startDate: yup.string().required(), - endDate: yup.string().required(), }), }; @@ -30,19 +26,14 @@ export default async ( await useAuth(req, res); await useValidate(schema, req, res); - const { websiteId, sessionId, startDate, endDate } = req.query; + const { websiteId, sessionId } = req.query; if (req.method === 'GET') { if (!(await canViewWebsite(req.auth, websiteId))) { return unauthorized(res); } - const data = await getSessionActivity( - websiteId, - sessionId, - new Date(startDate + 'Z'), - new Date(endDate + 'Z'), - ); + const data = await getSessionActivity(websiteId, sessionId); return ok(res, data); } diff --git a/src/queries/analytics/sessions/getSessionActivity.ts b/src/queries/analytics/sessions/getSessionActivity.ts index bb7c141c..47c5f590 100644 --- a/src/queries/analytics/sessions/getSessionActivity.ts +++ b/src/queries/analytics/sessions/getSessionActivity.ts @@ -2,44 +2,32 @@ import clickhouse from 'lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db'; import prisma from 'lib/prisma'; -export async function getSessionActivity( - ...args: [websiteId: string, sessionId: string, startDate: Date, endDate: Date] -) { +export async function getSessionActivity(...args: [websiteId: string, sessionId: string]) { return runQuery({ [PRISMA]: () => relationalQuery(...args), [CLICKHOUSE]: () => clickhouseQuery(...args), }); } -async function relationalQuery( - websiteId: string, - sessionId: string, - startDate: Date, - endDate: Date, -) { +async function relationalQuery(websiteId: string, sessionId: string) { return prisma.client.websiteEvent.findMany({ where: { id: sessionId, websiteId, - createdAt: { gte: startDate, lte: endDate }, }, + take: 500, }); } -async function clickhouseQuery( - websiteId: string, - sessionId: string, - startDate: Date, - endDate: Date, -) { - const { rawQuery } = clickhouse; +async function clickhouseQuery(websiteId: string, sessionId: string) { + const { rawQuery, getDateStringSQL } = clickhouse; return rawQuery( ` select session_id as id, website_id as websiteId, - created_at as createdAt, + ${getDateStringSQL('created_at')} as createdAt, url_path as urlPath, url_query as urlQuery, referrer_domain as referrerDomain, @@ -50,9 +38,9 @@ async function clickhouseQuery( from website_event where website_id = {websiteId:UUID} and session_id = {sessionId:UUID} - and created_at between {startDate:DateTime64} and {endDate:DateTime64} order by created_at desc + limit 500 `, - { websiteId, sessionId, startDate, endDate }, + { websiteId, sessionId }, ); } diff --git a/src/queries/analytics/sessions/getWebsiteSession.ts b/src/queries/analytics/sessions/getWebsiteSession.ts index 22c18642..6f672e7d 100644 --- a/src/queries/analytics/sessions/getWebsiteSession.ts +++ b/src/queries/analytics/sessions/getWebsiteSession.ts @@ -19,7 +19,7 @@ async function relationalQuery(websiteId: string, sessionId: string) { } async function clickhouseQuery(websiteId: string, sessionId: string) { - const { rawQuery } = clickhouse; + const { rawQuery, getDateStringSQL } = clickhouse; return rawQuery( ` @@ -34,8 +34,8 @@ async function clickhouseQuery(websiteId: string, sessionId: string) { country, subdivision1, city, - min(min_time) as firstAt, - max(max_time) as lastAt, + ${getDateStringSQL('min(min_time)')} as firstAt, + ${getDateStringSQL('max(max_time)')} as lastAt, uniq(visit_id) visits, sum(views) as views, sum(events) as events, diff --git a/src/queries/analytics/sessions/getWebsiteSessions.ts b/src/queries/analytics/sessions/getWebsiteSessions.ts index 60f30b6b..1ea3ef49 100644 --- a/src/queries/analytics/sessions/getWebsiteSessions.ts +++ b/src/queries/analytics/sessions/getWebsiteSessions.ts @@ -24,7 +24,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar } async function clickhouseQuery(websiteId: string, filters: QueryFilters, pageParams?: PageParams) { - const { pagedQuery, parseFilters } = clickhouse; + const { pagedQuery, parseFilters, getDateStringSQL } = clickhouse; const { params, dateQuery, filterQuery } = await parseFilters(websiteId, filters); return pagedQuery( @@ -42,8 +42,8 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar country, subdivision1, city, - min(min_time) as firstAt, - max(max_time) as lastAt, + ${getDateStringSQL('min(min_time)')} as firstAt, + ${getDateStringSQL('max(max_time)')} as lastAt, uniq(visit_id) as visits, sumIf(views, event_type = 1) as views from website_event_stats_hourly