"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 (
{title}
{value}
{helper}
Outcome metrics for revenue, customer experience, automation, and demand signals from AI-assisted storefront journeys.
{data.revenueImpact.methodology}
Conservative sentiment from storefront customer messages. Unknown is kept out of the chart.
{sentimentBars.every((row) => row.count === 0) ? (Shows the operational outcomes owners care about: handled questions, AI resolution, tickets, and response speed.
Timeline of demand, AI resolution, unresolved questions, and support tickets.
Product curiosity and repeated requests that can guide buying, merchandising, and product-page content.
{data.demandSignals.topProductQuestions.length === 0 ? (Conservative matching keeps revenue accurate. Pending attribution means cart interest exists but no matching order has been cached yet.
AI messages: {data.technicalDiagnostics.storefrontAiMessages}
Customer messages: {data.technicalDiagnostics.storefrontCustomerMessages}
Analytics events: {data.technicalDiagnostics.analyticsEvents}
Cached orders: {data.technicalDiagnostics.cachedOrders}