Yimaru-Admin/src/lib/analytics.ts
2026-05-18 08:44:51 -07:00

87 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { DashboardDateFilter, DateRevenue, LabelCount } from "../types/analytics.types"
const MONTH_SHORT = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
] as const
function formatShortDate(iso: string) {
const d = new Date(iso)
return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
}
function formatBreakdownLabel(label: string) {
return label.replace(/_/g, " ").toLowerCase()
}
export function getPrimaryQuestionTypeSummary(questionsByType: LabelCount[]): string {
if (questionsByType.length === 0) return "No question types"
const top = [...questionsByType].sort((a, b) => b.count - a.count)[0]
return `${top.count.toLocaleString()} ${formatBreakdownLabel(top.label)}`
}
export function getVideoLessonsSummary(lmsLessonsWithVideo = 0, examPrepLessonsWithVideo = 0): string {
return `${lmsLessonsWithVideo.toLocaleString()} LMS · ${examPrepLessonsWithVideo.toLocaleString()} exam prep lessons`
}
export interface MonthlyRevenuePoint {
month: string
monthIndex: number
revenue: number
}
export function aggregateRevenueByMonth(daily: DateRevenue[], year: number): MonthlyRevenuePoint[] {
const monthly = Array.from({ length: 12 }, (_, monthIndex) => ({
month: MONTH_SHORT[monthIndex],
monthIndex,
revenue: 0,
}))
for (const { date, revenue } of daily) {
const parsed = new Date(date)
if (parsed.getUTCFullYear() !== year) continue
monthly[parsed.getUTCMonth()].revenue += revenue
}
return monthly
}
export function formatRevenueAxisTick(value: number): string {
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(0)}M`
if (value >= 1_000) return `${Math.round(value / 1_000)}K`
return String(value)
}
export function getSeriesPeriodLabel(dateFilter?: DashboardDateFilter): string {
if (!dateFilter) return "Last 30 Days"
switch (dateFilter.mode) {
case "all_time":
return "Last 30 Days"
case "year":
return dateFilter.year != null ? String(dateFilter.year) : "Selected year"
case "year_month":
if (dateFilter.year != null && dateFilter.month != null) {
return `${MONTH_SHORT[dateFilter.month - 1]} ${dateFilter.year}`
}
return "Selected month"
case "custom":
if (dateFilter.from && dateFilter.to) {
return `${formatShortDate(dateFilter.from)} ${formatShortDate(dateFilter.to)}`
}
return "Custom range"
default:
return "Selected period"
}
}