"use client"; import { useEffect, useState } from "react"; interface FeatureAdoption { name: string; count: number; pct: number; } interface FamilyEngagement { id: string; name: string; tier: string; createdAt: string | null; lastActivity: string | null; activeStatus: "7d" | "30d" | "inactive" | "never"; feedCount: number; diaperCount: number; sleepCount: number; vaccinationCount: number; growthCount: number; memoryCount: number; chatCount: number; totalLogs: number; } interface EngagementData { totalFamilies: number; featureAdoption: FeatureAdoption[]; families: FamilyEngagement[]; activitySummary: { active7d: number; active30d: number; neverActive: number; total: number }; aiUsage: { totalCalls: number; totalTokens: number; totalCostPaise: number; familiesUsingAI: number }; logsByDay: { date: string; count: number }[]; } type Tab = "overview" | "families" | "ai"; type SortField = "lastActivity" | "totalLogs" | "name"; type ActivityFilter = "all" | "7d" | "30d" | "inactive" | "never"; export default function AdminAnalytics() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [tab, setTab] = useState("overview"); const [sortField, setSortField] = useState("lastActivity"); const [sortAsc, setSortAsc] = useState(false); const [activityFilter, setActivityFilter] = useState("all"); useEffect(() => { fetch("/api/admin/engagement", { credentials: "include" }) .then(r => r.json()) .then(d => { setData(d); setLoading(false); }) .catch(() => setLoading(false)); }, []); if (loading) return
Loading...
; if (!data) return
Failed to load analytics
; const handleSort = (field: SortField) => { if (sortField === field) setSortAsc(a => !a); else { setSortField(field); setSortAsc(false); } }; const sortedFamilies = [...data.families] .filter(f => activityFilter === "all" || f.activeStatus === activityFilter) .sort((a, b) => { let diff = 0; if (sortField === "lastActivity") { const ta = a.lastActivity ? new Date(a.lastActivity).getTime() : 0; const tb = b.lastActivity ? new Date(b.lastActivity).getTime() : 0; diff = tb - ta; } else if (sortField === "totalLogs") { diff = b.totalLogs - a.totalLogs; } else { diff = a.name.localeCompare(b.name); } return sortAsc ? -diff : diff; }); const maxLog = Math.max(...data.logsByDay.map(d => d.count), 1); const { aiUsage, activitySummary } = data; const costINR = (aiUsage.totalCostPaise / 100).toFixed(2); const costPerFamily = aiUsage.familiesUsingAI > 0 ? (aiUsage.totalCostPaise / 100 / aiUsage.familiesUsingAI).toFixed(2) : "0.00"; return (

Analytics

User journey and feature engagement

{(["overview", "families", "ai"] as Tab[]).map(t => ( ))}
{/* Activity Summary Cards — always visible */}
{tab === "overview" && ( <> {/* Feature Adoption Funnel */}

Feature Adoption

{data.featureAdoption.map(f => (
{f.name}
{f.pct}% ({f.count})
))} {data.featureAdoption.length === 0 && (
No data yet
)}
{/* Daily Activity Chart */}

Daily Activity — Last 30 Days

{data.logsByDay.slice(-30).map((d, i) => (
0 ? "4px" : "0" }} />
{d.date?.slice(5) || ""}
))} {data.logsByDay.length === 0 && (
No activity in the last 30 days
)}
)} {tab === "families" && (
{(["all", "7d", "30d", "inactive", "never"] as ActivityFilter[]).map(f => ( ))} {sortedFamilies.length} families
{sortedFamilies.map(f => ( ))}
Family Tier Features Used AI Chats
{f.name}
{f.createdAt?.slice(0, 10)}
{f.tier} {f.lastActivity ? ( {f.lastActivity.slice(0, 10)} ) : ( Never )} {f.totalLogs}
{f.feedCount > 0 && } {f.sleepCount > 0 && } {f.diaperCount > 0 && } {f.vaccinationCount > 0 && } {f.growthCount > 0 && } {f.memoryCount > 0 && } {f.chatCount > 0 && } {f.totalLogs === 0 && f.memoryCount === 0 && f.chatCount === 0 && ( None )}
{f.chatCount || "—"}
{sortedFamilies.length === 0 && (
No families match this filter
)}
)} {tab === "ai" && (

AI Cost Breakdown

Total cost (30 days) ₹{costINR}
Avg cost per AI-using family ₹{costPerFamily}
Total tokens used {aiUsage.totalTokens.toLocaleString()}
Families using AI {aiUsage.familiesUsingAI} / {data.totalFamilies} ({data.totalFamilies > 0 ? Math.round(aiUsage.familiesUsingAI / data.totalFamilies * 100) : 0}%)
)}
); } function SummaryCard({ label, value, color, sub }: { label: string; value: string | number; color: string; sub?: string }) { return (
{value}
{label}
{sub &&
{sub}
}
); } function FeatureBadge({ emoji, label }: { emoji: string; label: string }) { return ( {emoji} ); } function SortHeader({ label, field, current, asc, onSort }: { label: string; field: SortField; current: SortField; asc: boolean; onSort: (f: SortField) => void; }) { return ( onSort(field)} > {label} {current === field ? (asc ? "↑" : "↓") : "↕"} ); }