"use client" import { useEffect, useMemo, useState } from "react" import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis, } from "recharts" import { Loader2, Sparkles } from "lucide-react" import { useTheme } from "@/components/ThemeProvider" import { chartTooltipProps } from "@/lib/charts/rechartsTooltip" import { cn } from "@/lib/utils" type TimelineRow = { key: string label: string directUpsellRevenue: number directCrossSellRevenue: number aiAssistedRevenue: number questions: number resolvedByAi: number unresolvedQuestions: number ticketsCreated: number upsellShown: number upsellClicked: number cartActions: number positiveSentiment: number neutralSentiment: number negativeSentiment: number urgentSentiment: number } type AiAnalyticsPayload = { generatedAt: string range: string grain: string revenueImpact: { currency: string directUpsellRevenue: number directCrossSellRevenue: number aiAssistedRevenue: number aiCartConversionRate: number averageAiInfluencedOrderValue: number pendingAttributionCount: number methodology: string } customerExperience: { sentimentMix: { totals: Record<"positive" | "neutral" | "negative" | "urgent" | "unknown", number> percentages: Record<"positive" | "neutral" | "negative" | "urgent" | "unknown", number> } unresolvedQuestionRate: number escalationRate: number unresolvedQuestions: number ticketsCreated: number negativeOrUrgent: number } automationOutcomes: { questionsAnswered: number aiAnswers: number resolvedByAi: number ticketsCreated: number aiMedianSeconds: number manualMedianMinutes: number sampleAiPairs: number sampleManualPairs: number hoursSavedEstimate: number resolutionRate: number } demandSignals: { curiousProductQuestionCount: number topProductQuestions: { name: string; count: number }[] highInterestProducts: { name: string; count: number }[] questionMix: { name: string; count: number }[] } timeline: TimelineRow[] technicalDiagnostics: { hiddenByDefault: boolean storefrontAiMessages: number storefrontCustomerMessages: number analyticsEvents: number cachedOrders: number } } const RANGE_OPTIONS = [ { value: "today", label: "Today" }, { value: "7d", label: "7 days" }, { value: "30d", label: "30 days" }, { value: "90d", label: "90 days" }, { value: "12m", label: "12 months" }, { value: "year", label: "Year" }, { value: "all", label: "All" }, ] as const const SENTIMENT_COLORS = { positive: "#22c55e", neutral: "#94a3b8", negative: "#f97316", urgent: "#ef4444", } function formatMoney(amount: number, currency: string) { try { return new Intl.NumberFormat(undefined, { style: "currency", currency }).format(amount) } catch { return `${currency} ${amount.toFixed(2)}` } } function formatPercent(value: number) { return `${value.toFixed(value % 1 === 0 ? 0 : 1)}%` } function EmptyState({ children, isLight }: { children: string; isLight: boolean }) { return (
{children}
) } function MetricCard({ title, value, helper, accent, isLight, }: { title: string value: string helper: string accent: string isLight: boolean }) { return (

{title}

{value}

{helper}

) } export default function AiAnalyticsPage() { const { theme } = useTheme() const isLight = theme === "light" const [range, setRange] = useState("30d") const [data, setData] = useState(null) const [error, setError] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { let cancelled = false setLoading(true) setError(null) ;(async () => { try { const res = await fetch(`/api/dashboard/ai-analytics?range=${encodeURIComponent(range)}`) const json = await res.json().catch(() => null) if (!res.ok) throw new Error(json?.message || "Failed to load analytics") if (!cancelled) setData(json) } catch (e) { if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load analytics") } finally { if (!cancelled) setLoading(false) } })() return () => { cancelled = true } }, [range]) const chartMuted = isLight ? "#64748b" : "#94a3b8" const gridStroke = isLight ? "rgba(0,0,0,0.06)" : "rgba(255,255,255,0.08)" const tt = useMemo(() => chartTooltipProps(isLight), [isLight]) const timeline = data?.timeline ?? [] const sentimentBars = useMemo(() => { const totals = data?.customerExperience.sentimentMix.totals if (!totals) return [] return [ { name: "Positive", count: totals.positive, fill: SENTIMENT_COLORS.positive }, { name: "Neutral", count: totals.neutral, fill: SENTIMENT_COLORS.neutral }, { name: "Negative", count: totals.negative, fill: SENTIMENT_COLORS.negative }, { name: "Urgent", count: totals.urgent, fill: SENTIMENT_COLORS.urgent }, ] }, [data?.customerExperience.sentimentMix.totals]) return (

AI Business Analytics

Outcome metrics for revenue, customer experience, automation, and demand signals from AI-assisted storefront journeys.

{RANGE_OPTIONS.map((option) => ( ))}
{loading && (
)} {error && (
{error}
)} {!loading && data && ( <>

Revenue Impact Timeline

{data.revenueImpact.methodology}

{data.grain} view
{timeline.length === 0 ? ( Not enough data yet to draw a revenue timeline. ) : (
[formatMoney(Number(value ?? 0), data.revenueImpact.currency), String(name)]} />
)}

Customer Sentiment

Conservative sentiment from storefront customer messages. Unknown is kept out of the chart.

{sentimentBars.every((row) => row.count === 0) ? ( Not enough sentiment data yet. ) : (
{sentimentBars.map((row) => ( ))}
)}

Automation Outcomes

Shows the operational outcomes owners care about: handled questions, AI resolution, tickets, and response speed.

Questions And Resolutions

Timeline of demand, AI resolution, unresolved questions, and support tickets.

Growth Signals

Product curiosity and repeated requests that can guide buying, merchandising, and product-page content.

{data.demandSignals.topProductQuestions.length === 0 ? ( Not enough product-question data yet. ) : (
{data.demandSignals.topProductQuestions.map((row) => (
{row.name} {row.count}
))}
)}

Attribution Health

Conservative matching keeps revenue accurate. Pending attribution means cart interest exists but no matching order has been cached yet.

Technical Diagnostics

AI messages: {data.technicalDiagnostics.storefrontAiMessages}

Customer messages: {data.technicalDiagnostics.storefrontCustomerMessages}

Analytics events: {data.technicalDiagnostics.analyticsEvents}

Cached orders: {data.technicalDiagnostics.cachedOrders}

)}
) }