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 { MetricCard } from './MetricCard';
|
||||||
import { formatNumber, formatShortTime } from '../utils/common';
|
import { formatNumber, formatShortTime } from '../utils/common';
|
||||||
import { useTheme } from '../hooks/useTheme';
|
import { useTheme } from '../hooks/useTheme';
|
||||||
|
import { WebsiteOnlineCount } from './WebsiteOnlineCount';
|
||||||
|
|
||||||
interface WebsiteOverviewProps {
|
interface WebsiteOverviewProps {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
@ -110,6 +111,13 @@ const WebsiteOverviewItem: React.FC<{
|
|||||||
status: 'health',
|
status: 'health',
|
||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div className="ml-4 text-base font-normal">
|
||||||
|
<WebsiteOnlineCount
|
||||||
|
workspaceId={props.website.workspaceId}
|
||||||
|
websiteId={props.website.id}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
URL_LENGTH,
|
URL_LENGTH,
|
||||||
} from '../utils/const';
|
} from '../utils/const';
|
||||||
import type { DynamicData } from '../utils/types';
|
import type { DynamicData } from '../utils/types';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
export interface WebsiteEventPayload {
|
export interface WebsiteEventPayload {
|
||||||
data?: object;
|
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 * as trpcExpress from '@trpc/server/adapters/express';
|
||||||
import { createContext, publicProcedure, router } from './trpc';
|
import { createContext, router } from './trpc';
|
||||||
import { z } from 'zod';
|
|
||||||
import { notificationRouter } from './routers/notification';
|
import { notificationRouter } from './routers/notification';
|
||||||
|
import { websiteRouter } from './routers/website';
|
||||||
|
|
||||||
const appRouter = router({
|
const appRouter = router({
|
||||||
debug: publicProcedure.input(z.string()).query((opts) => {
|
website: websiteRouter,
|
||||||
return { id: opts.input, name: 'Bilbo' };
|
|
||||||
}),
|
|
||||||
notification: notificationRouter,
|
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