"use client"; /** * Phase 8 — org ANALYTICS tab (read-only usage/health analytics). * * Data: `GET /orgs/:orgId/admin/analytics` (server-side `assertOrgAdmin`, * org-scoped — see apps/api `analytics.service.ts`). The Overview tab is the * billing-adjacent counts + storage/audit trend; this tab is the usage/health * picture: content mix by page kind, growth (7d/30d), comment + file volume, * top audit actions, and the four 30-day trends. Rendering reuses the * Overview tab's house chrome (Section from settings-shell, CSS Sparkline, * Stat card, formatBytes) — no new dependencies. */ import { useQuery } from "@tanstack/react-query"; import { Activity, Database, FileText, MessageSquare, NotebookText, Users, type LucideIcon } from "lucide-react"; import { orgAdminApi } from "@/lib/org-admin"; import { Section } from "@/components/settings/settings-shell"; function formatBytes(n: number): string { if (n < 1024) return `${n} B`; const units = ["KB", "MB", "GB", "TB"]; let v = n / 1024; let i = 0; while (v >= 1024 && i < units.length - 1) { v /= 1024; i += 1; } return `${v.toFixed(1)} ${units[i]}`; } function Sparkline({ points, label, fmt }: { points: { day: string; value: number }[]; label: string; fmt: (n: number) => string }) { const max = Math.max(1, ...points.map((p) => p.value)); return (
Loading analytics…
; } if (q.isError) { returnCould not load analytics.
; } const a = q.data!.data; return (No pages yet.
) : (No audit events in the last 30 days.
) : (