feat: add website online count
This commit is contained in:
parent
a3eb5a14eb
commit
6d1c4e7d17
26
src/client/components/WebsiteOnlineCount.tsx
Normal file
26
src/client/components/WebsiteOnlineCount.tsx
Normal file
@ -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 (
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-2.5 h-2.5 rounded-full bg-green-500" />
|
||||
<span>{count} current visitor</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
WebsiteOnlineCount.displayName = 'WebsiteOnlineCount';
|
@ -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',
|
||||
}))}
|
||||
/>
|
||||
|
||||
<div className="ml-4 text-base font-normal">
|
||||
<WebsiteOnlineCount
|
||||
workspaceId={props.website.workspaceId}
|
||||
websiteId={props.website.id}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
@ -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<number> {
|
||||
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;
|
||||
}
|
||||
|
@ -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,
|
||||
});
|
||||
|
||||
|
19
src/server/trpc/routers/website.ts
Normal file
19
src/server/trpc/routers/website.ts
Normal file
@ -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;
|
||||
}),
|
||||
});
|
Loading…
Reference in New Issue
Block a user