42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import { prisma } from "@/lib/db";
|
|
import { analyticsEventSchema, type AnalyticsEventInput } from "@/lib/validations/analytics";
|
|
|
|
export async function recordAnalyticsEvent(input: unknown) {
|
|
const parsed = analyticsEventSchema.safeParse(input);
|
|
if (!parsed.success) return false;
|
|
|
|
const { type, path, entityId } = parsed.data;
|
|
await prisma.analyticsEvent.create({
|
|
data: {
|
|
type,
|
|
path: path || null,
|
|
projectId: type === "PROJECT_OPEN" || type === "PROJECT_LINK_CLICK" ? entityId || null : null,
|
|
melodyId: type === "MELODY_PLAY" ? entityId || null : null,
|
|
},
|
|
});
|
|
return true;
|
|
}
|
|
|
|
export async function getAnalyticsSummary() {
|
|
const since = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
const [total, grouped, recent] = await Promise.all([
|
|
prisma.analyticsEvent.count(),
|
|
prisma.analyticsEvent.groupBy({
|
|
by: ["type"],
|
|
where: { createdAt: { gte: since } },
|
|
_count: { _all: true },
|
|
orderBy: { _count: { type: "desc" } },
|
|
}),
|
|
prisma.analyticsEvent.findMany({
|
|
where: { createdAt: { gte: since } },
|
|
orderBy: { createdAt: "desc" },
|
|
take: 12,
|
|
select: { id: true, type: true, path: true, createdAt: true },
|
|
}),
|
|
]);
|
|
|
|
return { total, since, grouped, recent };
|
|
}
|
|
|
|
export type { AnalyticsEventInput };
|