From 6d1c4e7d177e75edef7188eb149e8cf7ad8cd333 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Thu, 28 Sep 2023 18:01:04 +0800 Subject: [PATCH] feat: add website online count --- src/client/components/WebsiteOnlineCount.tsx | 26 ++++++++++++++++++++ src/client/components/WebsiteOverview.tsx | 8 ++++++ src/server/model/website.ts | 18 ++++++++++++++ src/server/trpc/index.ts | 8 +++--- src/server/trpc/routers/website.ts | 19 ++++++++++++++ 5 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 src/client/components/WebsiteOnlineCount.tsx create mode 100644 src/server/trpc/routers/website.ts diff --git a/src/client/components/WebsiteOnlineCount.tsx b/src/client/components/WebsiteOnlineCount.tsx new file mode 100644 index 0000000..50ce6f1 --- /dev/null +++ b/src/client/components/WebsiteOnlineCount.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { trpc } from '../api/trpc'; + +export const WebsiteOnlineCount: React.FC<{ + workspaceId: string; + websiteId: string; +}> = React.memo((props) => { + const { workspaceId, websiteId } = props; + + const { data: count } = trpc.website.onlineCount.useQuery({ + workspaceId, + websiteId, + }); + + if (typeof count === 'number' && count > 0) { + return ( +
+
+ {count} current visitor +
+ ); + } + + return null; +}); +WebsiteOnlineCount.displayName = 'WebsiteOnlineCount'; diff --git a/src/client/components/WebsiteOverview.tsx b/src/client/components/WebsiteOverview.tsx index 2ad4749..08aea41 100644 --- a/src/client/components/WebsiteOverview.tsx +++ b/src/client/components/WebsiteOverview.tsx @@ -23,6 +23,7 @@ import { useEvent } from '../hooks/useEvent'; import { MetricCard } from './MetricCard'; import { formatNumber, formatShortTime } from '../utils/common'; import { useTheme } from '../hooks/useTheme'; +import { WebsiteOnlineCount } from './WebsiteOnlineCount'; interface WebsiteOverviewProps { workspaceId: string; @@ -110,6 +111,13 @@ const WebsiteOverviewItem: React.FC<{ status: 'health', }))} /> + +
+ +
diff --git a/src/server/model/website.ts b/src/server/model/website.ts index cbe6d9c..4719962 100644 --- a/src/server/model/website.ts +++ b/src/server/model/website.ts @@ -10,6 +10,7 @@ import { URL_LENGTH, } from '../utils/const'; import type { DynamicData } from '../utils/types'; +import dayjs from 'dayjs'; export interface WebsiteEventPayload { data?: object; @@ -255,3 +256,20 @@ export async function saveWebsiteSessionData(data: { }), ]); } + +export async function getWebsiteOnlineUserCount( + websiteId: string +): Promise { + const startAt = dayjs().subtract(5, 'minutes').toDate(); + + interface Ret { + x: number; + } + + const res = await prisma.$queryRaw< + Ret[] + >`SELECT count(distinct "sessionId") x FROM "WebsiteEvent" where "websiteId" = ${websiteId}::uuid AND "createdAt" >= ${startAt}`; + console.log('res', res); + + return res?.[0].x ?? 0; +} diff --git a/src/server/trpc/index.ts b/src/server/trpc/index.ts index 449a4a0..1a23390 100644 --- a/src/server/trpc/index.ts +++ b/src/server/trpc/index.ts @@ -1,12 +1,10 @@ import * as trpcExpress from '@trpc/server/adapters/express'; -import { createContext, publicProcedure, router } from './trpc'; -import { z } from 'zod'; +import { createContext, router } from './trpc'; import { notificationRouter } from './routers/notification'; +import { websiteRouter } from './routers/website'; const appRouter = router({ - debug: publicProcedure.input(z.string()).query((opts) => { - return { id: opts.input, name: 'Bilbo' }; - }), + website: websiteRouter, notification: notificationRouter, }); diff --git a/src/server/trpc/routers/website.ts b/src/server/trpc/routers/website.ts new file mode 100644 index 0000000..984ef33 --- /dev/null +++ b/src/server/trpc/routers/website.ts @@ -0,0 +1,19 @@ +import { router, workspaceProcedure } from '../trpc'; +import { z } from 'zod'; +import { getWebsiteOnlineUserCount } from '../../model/website'; + +export const websiteRouter = router({ + onlineCount: workspaceProcedure + .input( + z.object({ + websiteId: z.string(), + }) + ) + .query(async ({ input }) => { + const websiteId = input.websiteId; + + const count = await getWebsiteOnlineUserCount(websiteId); + + return count; + }), +});