feat: add session count
This commit is contained in:
parent
90166346e8
commit
d5acf872a9
@ -140,5 +140,9 @@ export function useWorkspaceWebsitePageview(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { stats: data?.stats ?? [], isLoading };
|
return {
|
||||||
|
pageviews: data?.pageviews ?? [],
|
||||||
|
sessions: data?.sessions ?? [],
|
||||||
|
isLoading,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ const WebsiteOverviewItem: React.FC<{
|
|||||||
const startDate = dayjs().subtract(1, 'day').add(1, unit).startOf(unit);
|
const startDate = dayjs().subtract(1, 'day').add(1, unit).startOf(unit);
|
||||||
const endDate = dayjs().endOf(unit);
|
const endDate = dayjs().endOf(unit);
|
||||||
|
|
||||||
const { stats, isLoading } = useWorkspaceWebsitePageview(
|
const { pageviews, sessions, isLoading } = useWorkspaceWebsitePageview(
|
||||||
props.website.workspaceId,
|
props.website.workspaceId,
|
||||||
props.website.id,
|
props.website.id,
|
||||||
startDate.unix() * 1000,
|
startDate.unix() * 1000,
|
||||||
@ -55,8 +55,14 @@ const WebsiteOverviewItem: React.FC<{
|
|||||||
);
|
);
|
||||||
|
|
||||||
const chartData = useMemo(() => {
|
const chartData = useMemo(() => {
|
||||||
return getDateArray(stats, startDate, endDate, unit);
|
const pageviewsArr = getDateArray(pageviews, startDate, endDate, unit);
|
||||||
}, [stats, unit]);
|
const sessionsArr = getDateArray(sessions, startDate, endDate, unit);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...pageviewsArr.map((item) => ({ ...item, type: 'pageview' })),
|
||||||
|
...sessionsArr.map((item) => ({ ...item, type: 'session' })),
|
||||||
|
];
|
||||||
|
}, [pageviews, sessions, unit]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
@ -138,14 +144,16 @@ const MetricCard: React.FC<{
|
|||||||
MetricCard.displayName = 'MetricCard';
|
MetricCard.displayName = 'MetricCard';
|
||||||
|
|
||||||
export const StatsChart: React.FC<{
|
export const StatsChart: React.FC<{
|
||||||
data: { x: string; y: number }[];
|
data: { x: string; y: number; type: string }[];
|
||||||
unit: DateUnit;
|
unit: DateUnit;
|
||||||
}> = React.memo((props) => {
|
}> = React.memo((props) => {
|
||||||
const config: ColumnConfig = useMemo(
|
const config: ColumnConfig = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
data: props.data,
|
data: props.data,
|
||||||
|
isStack: true,
|
||||||
xField: 'x',
|
xField: 'x',
|
||||||
yField: 'y',
|
yField: 'y',
|
||||||
|
seriesField: 'type',
|
||||||
label: {
|
label: {
|
||||||
position: 'middle' as const,
|
position: 'middle' as const,
|
||||||
style: {
|
style: {
|
||||||
|
@ -104,32 +104,6 @@ export async function deleteWorkspaceWebsite(
|
|||||||
return website;
|
return website;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getWorkspaceWebsitePageviewStats(
|
|
||||||
websiteId: string,
|
|
||||||
filters: QueryFilters
|
|
||||||
) {
|
|
||||||
const { timezone = 'utc', unit = 'day' } = filters;
|
|
||||||
const { filterQuery, joinSession, params } = await parseFilters(websiteId, {
|
|
||||||
...filters,
|
|
||||||
eventType: EVENT_TYPE.pageView,
|
|
||||||
});
|
|
||||||
|
|
||||||
return prisma.$queryRaw`
|
|
||||||
select
|
|
||||||
${getDateQuery('"WebsiteEvent"."createdAt"', unit, timezone)} x,
|
|
||||||
count(1) y
|
|
||||||
from "WebsiteEvent"
|
|
||||||
${joinSession ? Prisma.sql([joinSession]) : Prisma.empty}
|
|
||||||
where "WebsiteEvent"."websiteId" = ${params.websiteId}::uuid
|
|
||||||
and "WebsiteEvent"."createdAt" between ${
|
|
||||||
params.startDate
|
|
||||||
}::timestamptz and ${params.endDate}::timestamptz
|
|
||||||
and "WebsiteEvent"."eventType" = ${EVENT_TYPE.pageView}
|
|
||||||
${filterQuery}
|
|
||||||
group by 1
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWorkspaceWebsiteDateRange(websiteId: string) {
|
export async function getWorkspaceWebsiteDateRange(websiteId: string) {
|
||||||
const { params } = await parseFilters(websiteId, {
|
const { params } = await parseFilters(websiteId, {
|
||||||
startDate: new Date(DEFAULT_RESET_DATE),
|
startDate: new Date(DEFAULT_RESET_DATE),
|
||||||
@ -155,3 +129,53 @@ export async function getWorkspaceWebsiteDateRange(websiteId: string) {
|
|||||||
min: res._min.createdAt,
|
min: res._min.createdAt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getWorkspaceWebsitePageviewStats(
|
||||||
|
websiteId: string,
|
||||||
|
filters: QueryFilters
|
||||||
|
) {
|
||||||
|
const { timezone = 'utc', unit = 'day' } = filters;
|
||||||
|
const { filterQuery, joinSession, params } = await parseFilters(websiteId, {
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
|
||||||
|
return prisma.$queryRaw`
|
||||||
|
select
|
||||||
|
${getDateQuery('"WebsiteEvent"."createdAt"', unit, timezone)} x,
|
||||||
|
count(1) y
|
||||||
|
from "WebsiteEvent"
|
||||||
|
${joinSession}
|
||||||
|
where "WebsiteEvent"."websiteId" = ${params.websiteId}::uuid
|
||||||
|
and "WebsiteEvent"."createdAt" between ${
|
||||||
|
params.startDate
|
||||||
|
}::timestamptz and ${params.endDate}::timestamptz
|
||||||
|
and "WebsiteEvent"."eventType" = ${EVENT_TYPE.pageView}
|
||||||
|
${filterQuery}
|
||||||
|
group by 1
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWorkspaceWebsiteSessionStats(
|
||||||
|
websiteId: string,
|
||||||
|
filters: QueryFilters
|
||||||
|
) {
|
||||||
|
const { timezone = 'utc', unit = 'day' } = filters;
|
||||||
|
const { filterQuery, joinSession, params } = await parseFilters(websiteId, {
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
|
||||||
|
return prisma.$queryRaw`
|
||||||
|
select
|
||||||
|
${getDateQuery('"WebsiteEvent"."createdAt"', unit, timezone)} x,
|
||||||
|
count(distinct "WebsiteEvent"."sessionId") y
|
||||||
|
from "WebsiteEvent"
|
||||||
|
${joinSession}
|
||||||
|
where "WebsiteEvent"."websiteId" = ${params.websiteId}::uuid
|
||||||
|
and "WebsiteEvent"."createdAt" between ${
|
||||||
|
params.startDate
|
||||||
|
}::timestamptz and ${params.endDate}::timestamptz
|
||||||
|
and "WebsiteEvent"."eventType" = ${EVENT_TYPE.pageView}
|
||||||
|
${filterQuery}
|
||||||
|
group by 1
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
getWorkspaceWebsiteInfo,
|
getWorkspaceWebsiteInfo,
|
||||||
getWorkspaceWebsitePageviewStats,
|
getWorkspaceWebsitePageviewStats,
|
||||||
getWorkspaceWebsites,
|
getWorkspaceWebsites,
|
||||||
|
getWorkspaceWebsiteSessionStats,
|
||||||
updateWorkspaceWebsiteInfo,
|
updateWorkspaceWebsiteInfo,
|
||||||
} from '../model/workspace';
|
} from '../model/workspace';
|
||||||
import { parseDateRange } from '../utils/common';
|
import { parseDateRange } from '../utils/common';
|
||||||
@ -186,11 +187,11 @@ workspaceRouter.get(
|
|||||||
city,
|
city,
|
||||||
};
|
};
|
||||||
|
|
||||||
const stats = await getWorkspaceWebsitePageviewStats(
|
const [pageviews, sessions] = await Promise.all([
|
||||||
websiteId,
|
getWorkspaceWebsitePageviewStats(websiteId, filters as QueryFilters),
|
||||||
filters as QueryFilters
|
getWorkspaceWebsiteSessionStats(websiteId, filters as QueryFilters),
|
||||||
);
|
]);
|
||||||
|
|
||||||
res.json({ stats });
|
res.json({ pageviews, sessions });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -58,8 +58,10 @@ export async function parseFilters(
|
|||||||
([key, value]) =>
|
([key, value]) =>
|
||||||
typeof value !== 'undefined' && SESSION_COLUMNS.includes(key)
|
typeof value !== 'undefined' && SESSION_COLUMNS.includes(key)
|
||||||
)
|
)
|
||||||
? `inner join "WebsiteSession" on "WebsiteEvent"."sessionId" = "WebsiteSession"."id"`
|
? Prisma.sql([
|
||||||
: '',
|
`inner join "WebsiteSession" on "WebsiteEvent"."sessionId" = "WebsiteSession"."id"`,
|
||||||
|
])
|
||||||
|
: Prisma.empty,
|
||||||
filterQuery: getFilterQuery(filters, options, websiteDomain),
|
filterQuery: getFilterQuery(filters, options, websiteDomain),
|
||||||
params: {
|
params: {
|
||||||
...normalizeFilters(filters),
|
...normalizeFilters(filters),
|
||||||
|
Loading…
Reference in New Issue
Block a user