growth-activities / src /lib /analytics.ts
3v324v23's picture
init: growth-activities for hf spaces
243dc36
Raw
History Blame Contribute Delete
2.22 kB
import type { ChannelPoint, DailyPoint, DayKey, Event, EventType, Kpis, Lead } from "@/lib/domain"
import { clamp, toDayKey } from "@/lib/time"
export function computeKpis(args: { events: Event[]; leads: Lead[] }): Kpis {
const uv = countUv(args.events)
const clicks = countType(args.events, "click")
const submits = countType(args.events, "submit")
const claims = countType(args.events, "claim")
const redeems = countType(args.events, "redeem")
const submitRate = uv ? submits / uv : 0
const redeemRate = submits ? redeems / submits : 0
return { uv, clicks, submits, claims, redeems, submitRate, redeemRate }
}
export function dailySeries(args: { events: Event[]; days: number }): DailyPoint[] {
const map = new Map<DayKey, DailyPoint>()
const types: EventType[] = ["view", "submit", "redeem"]
for (const e of args.events) {
if (!types.includes(e.type)) continue
const day = toDayKey(e.ts)
const cur = map.get(day) ?? { day, uv: 0, submits: 0, redeems: 0 }
if (e.type === "view") cur.uv += 1
if (e.type === "submit") cur.submits += 1
if (e.type === "redeem") cur.redeems += 1
map.set(day, cur)
}
const keys = Array.from(map.keys()).sort((a, b) => a.localeCompare(b))
const tail = keys.slice(Math.max(0, keys.length - args.days))
return tail.map((k) => map.get(k)!).map((p) => ({ ...p, uv: clamp(p.uv, 0, 999999) }))
}
export function channelSeries(args: { events: Event[]; max: number }): ChannelPoint[] {
const map = new Map<string, ChannelPoint>()
for (const e of args.events) {
const channel = (e.meta?.utm_source as string | undefined) ?? "direct"
const cur = map.get(channel) ?? { channel, uv: 0, submits: 0, redeems: 0 }
if (e.type === "view") cur.uv += 1
if (e.type === "submit") cur.submits += 1
if (e.type === "redeem") cur.redeems += 1
map.set(channel, cur)
}
return Array.from(map.values())
.sort((a, b) => b.uv - a.uv)
.slice(0, args.max)
}
export function countUv(events: Event[]) {
const views = events.filter((e) => e.type === "view")
return views.length
}
export function countType(events: Event[], type: EventType) {
return events.reduce((acc, e) => acc + (e.type === type ? 1 : 0), 0)
}