From a1c0ec9c81af9a1017d05ccbe117a58973740f6e Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 9 Aug 2024 15:49:30 -0700 Subject: [PATCH] update getSessionActivity / getWebsiteSession --- .../sessions/[sessionId]/SessionActivity.tsx | 6 +++- .../[sessionId]/SessionDetailsPage.tsx | 17 +++++++---- .../hooks/queries/useSessionActivity.ts | 9 ++++-- .../sessions/[sessionId]/activity.ts | 13 +++++++-- .../[websiteId]/sessions/[sessionId]/index.ts | 2 +- .../analytics/sessions/getSessionActivity.ts | 28 ++++++++++++++----- .../analytics/sessions/getWebsiteSession.ts | 24 ++++++++-------- 7 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx index 0a15430c..69407584 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx @@ -8,12 +8,16 @@ import styles from './SessionActivity.module.css'; export function SessionActivity({ websiteId, sessionId, + startDate, + endDate, }: { websiteId: string; sessionId: string; + startDate: string; + endDate: string; }) { const { locale } = useLocale(); - const { data, isLoading } = useSessionActivity(websiteId, sessionId); + const { data, isLoading } = useSessionActivity(websiteId, sessionId, startDate, endDate); 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 fa96c776..d6a07edc 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionDetailsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionDetailsPage.tsx @@ -1,13 +1,13 @@ 'use client'; -import WebsiteHeader from '../../WebsiteHeader'; -import SessionInfo from './SessionInfo'; -import { useWebsiteSession } from 'components/hooks'; import Avatar from 'components/common/Avatar'; +import { LoadingPanel } from 'components/common/LoadingPanel'; +import { useWebsiteSession } from 'components/hooks'; +import WebsiteHeader from '../../WebsiteHeader'; import { SessionActivity } from './SessionActivity'; -import { SessionStats } from './SessionStats'; import { SessionData } from './SessionData'; import styles from './SessionDetailsPage.module.css'; -import { LoadingPanel } from 'components/common/LoadingPanel'; +import SessionInfo from './SessionInfo'; +import { SessionStats } from './SessionStats'; export default function SessionDetailsPage({ websiteId, @@ -28,7 +28,12 @@ export default function SessionDetailsPage({
- +
diff --git a/src/components/hooks/queries/useSessionActivity.ts b/src/components/hooks/queries/useSessionActivity.ts index e6d7ffa0..94676a99 100644 --- a/src/components/hooks/queries/useSessionActivity.ts +++ b/src/components/hooks/queries/useSessionActivity.ts @@ -1,12 +1,17 @@ import { useApi } from './useApi'; -export function useSessionActivity(websiteId: string, sessionId: string) { +export function useSessionActivity( + websiteId: string, + sessionId: string, + startDate: string, + endDate: string, +) { const { get, useQuery } = useApi(); return useQuery({ queryKey: ['session:activity', { websiteId, sessionId }], queryFn: () => { - return get(`/websites/${websiteId}/sessions/${sessionId}/activity`); + return get(`/websites/${websiteId}/sessions/${sessionId}/activity`, { startDate, endDate }); }, }); } diff --git a/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts b/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts index 8d1b2346..2bf23654 100644 --- a/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts +++ b/src/pages/api/websites/[websiteId]/sessions/[sessionId]/activity.ts @@ -9,12 +9,16 @@ 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(), }), }; @@ -26,14 +30,19 @@ export default async ( await useAuth(req, res); await useValidate(schema, req, res); - const { websiteId, sessionId } = req.query; + const { websiteId, sessionId, startDate, endDate } = req.query; if (req.method === 'GET') { if (!(await canViewWebsite(req.auth, websiteId))) { return unauthorized(res); } - const data = await getSessionActivity(websiteId, sessionId); + const data = await getSessionActivity( + websiteId, + sessionId, + new Date(startDate), + new Date(endDate), + ); return ok(res, data); } diff --git a/src/pages/api/websites/[websiteId]/sessions/[sessionId]/index.ts b/src/pages/api/websites/[websiteId]/sessions/[sessionId]/index.ts index b2665c7c..f627a208 100644 --- a/src/pages/api/websites/[websiteId]/sessions/[sessionId]/index.ts +++ b/src/pages/api/websites/[websiteId]/sessions/[sessionId]/index.ts @@ -33,7 +33,7 @@ export default async ( return unauthorized(res); } - const data = await getWebsiteSession(sessionId); + const data = await getWebsiteSession(websiteId, sessionId); return ok(res, data); } diff --git a/src/queries/analytics/sessions/getSessionActivity.ts b/src/queries/analytics/sessions/getSessionActivity.ts index bc1f9aca..bb7c141c 100644 --- a/src/queries/analytics/sessions/getSessionActivity.ts +++ b/src/queries/analytics/sessions/getSessionActivity.ts @@ -1,24 +1,37 @@ -import prisma from 'lib/prisma'; import clickhouse from 'lib/clickhouse'; -import { runQuery, PRISMA, CLICKHOUSE } from 'lib/db'; +import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db'; +import prisma from 'lib/prisma'; -export async function getSessionActivity(...args: [websiteId: string, sessionId: string]) { +export async function getSessionActivity( + ...args: [websiteId: string, sessionId: string, startDate: Date, endDate: Date] +) { return runQuery({ [PRISMA]: () => relationalQuery(...args), [CLICKHOUSE]: () => clickhouseQuery(...args), }); } -async function relationalQuery(websiteId: string, sessionId: string) { +async function relationalQuery( + websiteId: string, + sessionId: string, + startDate: Date, + endDate: Date, +) { return prisma.client.websiteEvent.findMany({ where: { id: sessionId, websiteId, + createdAt: { gte: startDate, lte: endDate }, }, }); } -async function clickhouseQuery(websiteId: string, sessionId: string) { +async function clickhouseQuery( + websiteId: string, + sessionId: string, + startDate: Date, + endDate: Date, +) { const { rawQuery } = clickhouse; return rawQuery( @@ -36,9 +49,10 @@ async function clickhouseQuery(websiteId: string, sessionId: string) { visit_id as visitId from website_event where website_id = {websiteId:UUID} - and session_id = {sessionId:UUID} + and session_id = {sessionId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} order by created_at desc `, - { websiteId, sessionId }, + { websiteId, sessionId, startDate, endDate }, ); } diff --git a/src/queries/analytics/sessions/getWebsiteSession.ts b/src/queries/analytics/sessions/getWebsiteSession.ts index 38bc230c..ca527dba 100644 --- a/src/queries/analytics/sessions/getWebsiteSession.ts +++ b/src/queries/analytics/sessions/getWebsiteSession.ts @@ -2,22 +2,23 @@ import prisma from 'lib/prisma'; import clickhouse from 'lib/clickhouse'; import { runQuery, PRISMA, CLICKHOUSE } from 'lib/db'; -export async function getWebsiteSession(...args: [sessionId: string]) { +export async function getWebsiteSession(...args: [websiteId: string, sessionId: string]) { return runQuery({ [PRISMA]: () => relationalQuery(...args), [CLICKHOUSE]: () => clickhouseQuery(...args), }); } -async function relationalQuery(sessionId: string) { +async function relationalQuery(websiteId: string, sessionId: string) { return prisma.client.session.findUnique({ where: { id: sessionId, + websiteId, }, }); } -async function clickhouseQuery(sessionId: string) { +async function clickhouseQuery(websiteId: string, sessionId: string) { const { rawQuery } = clickhouse; return rawQuery( @@ -34,15 +35,16 @@ async function clickhouseQuery(sessionId: string) { country, subdivision1, city, - min(created_at) as firstAt, - max(created_at) as lastAt, + min(min_time) as firstAt, + max(max_time) as lastAt, uniq(visit_id) as visits, - sumIf(1, event_type = 1) as views, - sumIf(1, event_type = 2) as events - from website_event - where session_id = {sessionId:UUID} - group by session_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city + sumIf(views, event_type = 1) as views, + length(groupArrayArray(event_name)) as events + from website_event_stats_hourly + where website_id = {websiteId:UUID} + and session_id = {sessionId:UUID} + group by session_id, website_id, hostname, browser, os, device, screen, language, country, subdivision1, city; `, - { sessionId }, + { websiteId, sessionId }, ).then(result => result?.[0]); }