medusa-analytics 0.0.17 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useMemo } from "react";
3
3
  import { defineRouteConfig } from "@medusajs/admin-sdk";
4
- import { ChartBar } from "@medusajs/icons";
5
- import { Container, Heading, Text, Label, Button, Table } from "@medusajs/ui";
6
- import { ResponsiveContainer, ComposedChart, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Area, Line, LineChart, ReferenceLine, BarChart, Bar, Cell } from "recharts";
4
+ import { CurrencyDollar, ShoppingCart, TruckFast, Cash, ChartBar } from "@medusajs/icons";
5
+ import { Container, Text, Heading, Label, Button, Table } from "@medusajs/ui";
6
+ import { ResponsiveContainer, LineChart, CartesianGrid, XAxis, YAxis, Tooltip, Line, ComposedChart, Legend, Area, ReferenceLine, BarChart, Bar, PieChart, Pie, Cell, ScatterChart, Scatter } from "recharts";
7
7
  const ACCENT_STYLES = {
8
8
  blue: {
9
9
  border: "border-sky-400/30",
@@ -46,33 +46,40 @@ function AnalyticsDashboardHeader({
46
46
  title,
47
47
  description,
48
48
  actions,
49
- variant = "default"
49
+ variant = "default",
50
+ actionsBare = false,
51
+ appearance = "card"
50
52
  }) {
51
53
  const isPremium = variant === "premium";
52
- return /* @__PURE__ */ jsxs(
53
- Container,
54
+ const isInset = appearance === "inset";
55
+ const headerRow = /* @__PURE__ */ jsxs(
56
+ "div",
54
57
  {
55
- className: `overflow-hidden rounded-2xl border bg-ui-bg-base p-0 ${isPremium ? "border-ui-border-strong shadow-sm" : "border-ui-border-base shadow-sm"}`.trim(),
58
+ className: `flex flex-col gap-2 px-4 py-2.5 lg:flex-row lg:items-center lg:justify-between ${isPremium ? "border-b border-ui-border-base/80" : "border-b border-ui-border-base"}`.trim(),
56
59
  children: [
57
- /* @__PURE__ */ jsxs(
60
+ /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
61
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: isPremium ? "text-lg font-semibold tracking-tight" : "tracking-tight", children: title }),
62
+ description ? /* @__PURE__ */ jsx(Text, { className: `text-ui-fg-muted ${isPremium ? "max-w-2xl text-xs leading-snug" : "text-sm"}`.trim(), children: description }) : null
63
+ ] }),
64
+ actions ? actionsBare ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-3 self-start lg:self-auto", children: actions }) : /* @__PURE__ */ jsx(
58
65
  "div",
59
66
  {
60
- className: `flex flex-col gap-2 px-4 py-2.5 lg:flex-row lg:items-center lg:justify-between ${isPremium ? "border-b border-ui-border-base/80" : "border-b border-ui-border-base"}`.trim(),
61
- children: [
62
- /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
63
- /* @__PURE__ */ jsx(Heading, { level: "h2", className: isPremium ? "text-lg font-semibold tracking-tight" : "tracking-tight", children: title }),
64
- description ? /* @__PURE__ */ jsx(Text, { className: `text-ui-fg-muted ${isPremium ? "max-w-2xl text-xs leading-snug" : "text-sm"}`.trim(), children: description }) : null
65
- ] }),
66
- actions ? /* @__PURE__ */ jsx(
67
- "div",
68
- {
69
- className: `flex self-start rounded-xl border px-2 py-1.5 lg:self-auto ${isPremium ? "border-ui-border-strong bg-ui-bg-subtle shadow-[inset_0_1px_0_rgba(255,255,255,0.35)]" : "border-ui-border-base bg-ui-bg-subtle"}`.trim(),
70
- children: actions
71
- }
72
- ) : null
73
- ]
67
+ className: `flex self-start rounded-xl border px-2 py-1.5 lg:self-auto ${isPremium ? "border-ui-border-strong bg-ui-bg-subtle shadow-[inset_0_1px_0_rgba(255,255,255,0.35)]" : "border-ui-border-base bg-ui-bg-subtle"}`.trim(),
68
+ children: actions
74
69
  }
75
- ),
70
+ ) : null
71
+ ]
72
+ }
73
+ );
74
+ if (isInset) {
75
+ return /* @__PURE__ */ jsx("div", { className: "border-0 bg-transparent p-0 shadow-none", children: headerRow });
76
+ }
77
+ return /* @__PURE__ */ jsxs(
78
+ Container,
79
+ {
80
+ className: `overflow-hidden rounded-2xl border bg-ui-bg-base p-0 ${isPremium ? "border-ui-border-strong shadow-sm" : "border-ui-border-base shadow-sm"}`.trim(),
81
+ children: [
82
+ headerRow,
76
83
  /* @__PURE__ */ jsx(
77
84
  "div",
78
85
  {
@@ -143,23 +150,24 @@ function AnalyticsSection({
143
150
  actions,
144
151
  children,
145
152
  className,
146
- variant = "default"
153
+ variant = "default",
154
+ actionsBare = false
147
155
  }) {
148
156
  const isAtlas = variant === "atlas";
149
157
  const isPremium = variant !== "default" && !isAtlas;
150
158
  const shellClass = isAtlas ? "overflow-hidden rounded-lg border border-ui-border-base bg-ui-bg-base shadow-sm" : `overflow-hidden rounded-2xl border bg-ui-bg-base p-0 ${isPremium ? "border-ui-border-strong shadow-sm" : "border-ui-border-base shadow-sm"}`.trim();
151
- const headerClass = isAtlas ? "flex flex-col gap-1.5 border-b border-ui-border-base bg-ui-bg-subtle/40 px-4 py-2.5 lg:flex-row lg:items-center lg:justify-between" : `flex flex-col gap-2 px-4 py-2.5 lg:flex-row lg:items-center lg:justify-between ${isPremium ? "border-b border-ui-border-base/80" : "border-b border-ui-border-base"}`.trim();
159
+ const headerClass = isAtlas ? "flex flex-col gap-1 border-b border-ui-border-base bg-ui-bg-subtle/40 px-3 py-2 lg:flex-row lg:items-center lg:justify-between" : `flex flex-col gap-2 px-4 py-2.5 lg:flex-row lg:items-center lg:justify-between ${isPremium ? "border-b border-ui-border-base/80" : "border-b border-ui-border-base"}`.trim();
152
160
  const titleClass = isAtlas ? "text-sm font-semibold tracking-tight text-ui-fg-base" : isPremium ? "text-base font-semibold tracking-tight" : "tracking-tight";
153
161
  const descClass = isAtlas ? "max-w-2xl text-[11px] leading-snug text-ui-fg-muted" : isPremium ? "max-w-2xl text-xs leading-snug" : "text-sm";
154
162
  const actionsShellClass = isAtlas ? "flex shrink-0 flex-wrap items-center gap-1.5 rounded-md border border-ui-border-base bg-ui-bg-base px-2 py-1" : `flex shrink-0 flex-wrap items-center gap-1.5 rounded-xl border px-2 py-1.5 ${isPremium ? "border-ui-border-strong bg-ui-bg-subtle shadow-[inset_0_1px_0_rgba(255,255,255,0.32)]" : "border-ui-border-base bg-ui-bg-subtle"}`.trim();
155
- const bodyClass = isAtlas ? "p-3" : variant === "hero" ? "px-4 py-3" : "px-4 py-3";
163
+ const bodyClass = isAtlas ? "p-2" : variant === "hero" ? "px-4 py-3" : "px-4 py-3";
156
164
  return /* @__PURE__ */ jsxs(Container, { className: `${shellClass} ${className ?? ""}`.trim(), children: [
157
165
  /* @__PURE__ */ jsxs("div", { className: headerClass, children: [
158
166
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-0.5", children: [
159
167
  /* @__PURE__ */ jsx(Heading, { level: "h3", className: titleClass, children: title }),
160
168
  description ? /* @__PURE__ */ jsx(Text, { className: `text-ui-fg-muted ${descClass}`.trim(), children: description }) : null
161
169
  ] }),
162
- actions ? /* @__PURE__ */ jsx("div", { className: actionsShellClass, children: actions }) : null
170
+ actions ? actionsBare ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: actions }) : /* @__PURE__ */ jsx("div", { className: actionsShellClass, children: actions }) : null
163
171
  ] }),
164
172
  /* @__PURE__ */ jsx("div", { className: bodyClass, children })
165
173
  ] });
@@ -169,7 +177,7 @@ function AnalyticsChartSurface({
169
177
  className,
170
178
  variant = "default"
171
179
  }) {
172
- const surfaceClassName = variant === "atlas" ? "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 p-2.5 shadow-sm" : variant === "glass" ? "rounded-xl border border-ui-border-strong bg-[linear-gradient(180deg,rgba(255,255,255,0.12),rgba(255,255,255,0.03))] p-2.5 shadow-[inset_0_1px_0_rgba(255,255,255,0.22)]" : variant === "panel" ? "rounded-xl border border-ui-border-base/90 bg-ui-bg-base p-2.5 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]" : "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-2 shadow-inner";
180
+ const surfaceClassName = variant === "atlas" ? "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 p-2 shadow-sm" : variant === "glass" ? "rounded-xl border border-ui-border-strong bg-[linear-gradient(180deg,rgba(255,255,255,0.12),rgba(255,255,255,0.03))] p-2.5 shadow-[inset_0_1px_0_rgba(255,255,255,0.22)]" : variant === "panel" ? "rounded-xl border border-ui-border-base/90 bg-ui-bg-base p-2.5 shadow-[inset_0_1px_0_rgba(255,255,255,0.18)]" : "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-2 shadow-inner";
173
181
  return /* @__PURE__ */ jsx(
174
182
  "div",
175
183
  {
@@ -189,7 +197,21 @@ function AnalyticsTableSurface({ children, className }) {
189
197
  }
190
198
  function isDailyOrderRow(value) {
191
199
  if (typeof value !== "object" || value === null) return false;
192
- return "date" in value && "orders_count" in value && "total_revenue" in value && typeof value.date === "string" && typeof value.orders_count === "number" && typeof value.total_revenue === "number";
200
+ const v = value;
201
+ return typeof v.date === "string" && typeof v.orders_count === "number" && typeof v.total_revenue === "number";
202
+ }
203
+ function nonCancelledRevenue(d) {
204
+ const delivered = d.revenue_delivered ?? 0;
205
+ const open = d.revenue_open ?? 0;
206
+ if (delivered > 0 || open > 0 || (d.revenue_cancelled ?? 0) > 0) {
207
+ return delivered + open;
208
+ }
209
+ return Math.max(0, d.total_revenue - (d.revenue_cancelled ?? 0));
210
+ }
211
+ function bucketAov(d) {
212
+ const ordNc = d.orders_count - d.cancelled_count;
213
+ if (ordNc <= 0) return 0;
214
+ return nonCancelledRevenue(d) / ordNc;
193
215
  }
194
216
  function isOrdersTodayPoint(value) {
195
217
  return isDailyOrderRow(value) && "isToday" in value && typeof value.isToday === "boolean";
@@ -219,6 +241,12 @@ function formatChartLabel(value) {
219
241
  function formatPercent(value) {
220
242
  return `${value.toFixed(1)}%`;
221
243
  }
244
+ function ordersCountFromPiePayload(payload) {
245
+ if (typeof payload !== "object" || payload === null) return 0;
246
+ if (!("orders_count" in payload)) return 0;
247
+ const c = payload.orders_count;
248
+ return Math.floor(Number(c) || 0);
249
+ }
222
250
  function formatShortNumber(value) {
223
251
  return new Intl.NumberFormat("en-IN", {
224
252
  notation: "compact",
@@ -327,33 +355,102 @@ const KPI_ICON_BG = {
327
355
  purple: "bg-violet-500/20",
328
356
  amber: "bg-amber-500/20"
329
357
  };
358
+ const KPI_ICONS = {
359
+ green: CurrencyDollar,
360
+ blue: ShoppingCart,
361
+ purple: TruckFast,
362
+ amber: Cash
363
+ };
364
+ const PIE_PALETTE = ["#6366F1", "#94A3B8", "#10B981", "#F59E0B"];
365
+ function TrafficRevenueDonut({
366
+ traffic,
367
+ compact = false
368
+ }) {
369
+ const innerRadius = compact ? 28 : 34;
370
+ const outerRadius = compact ? 44 : 54;
371
+ return /* @__PURE__ */ jsx("div", { className: compact ? "h-[118px] w-full" : "h-[152px] w-full shrink-0", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { margin: { top: 2, right: 2, left: 2, bottom: 2 }, children: [
372
+ /* @__PURE__ */ jsx(
373
+ Pie,
374
+ {
375
+ data: traffic,
376
+ dataKey: "revenue",
377
+ nameKey: "label",
378
+ cx: "50%",
379
+ cy: "48%",
380
+ innerRadius,
381
+ outerRadius,
382
+ paddingAngle: 2,
383
+ children: traffic.map((_, i) => /* @__PURE__ */ jsx(Cell, { fill: PIE_PALETTE[i % PIE_PALETTE.length] }, `traffic-slice-${i}`))
384
+ }
385
+ ),
386
+ /* @__PURE__ */ jsx(
387
+ Tooltip,
388
+ {
389
+ content: ({ active, payload }) => {
390
+ var _a, _b, _c;
391
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxs(TooltipCard, { title: String(((_a = payload[0]) == null ? void 0 : _a.name) ?? ""), children: [
392
+ /* @__PURE__ */ jsxs("div", { children: [
393
+ "Revenue:",
394
+ " ",
395
+ /* @__PURE__ */ jsx("strong", { children: formatCurrency$1(Number((_b = payload[0]) == null ? void 0 : _b.value) || 0) })
396
+ ] }),
397
+ /* @__PURE__ */ jsxs("div", { children: [
398
+ "Orders:",
399
+ " ",
400
+ /* @__PURE__ */ jsx("strong", { children: ordersCountFromPiePayload((_c = payload[0]) == null ? void 0 : _c.payload).toLocaleString() })
401
+ ] })
402
+ ] }) : null;
403
+ }
404
+ }
405
+ ),
406
+ /* @__PURE__ */ jsx(
407
+ Legend,
408
+ {
409
+ wrapperStyle: { fontSize: compact ? 8 : 9, paddingTop: 0 },
410
+ verticalAlign: "bottom",
411
+ height: compact ? 18 : 22,
412
+ iconType: "circle"
413
+ }
414
+ )
415
+ ] }) }) });
416
+ }
417
+ function TrafficSourcesOverviewCard({
418
+ traffic,
419
+ loading,
420
+ error,
421
+ totalRevenue,
422
+ windowLabel
423
+ }) {
424
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-[132px] flex-col rounded-2xl border border-ui-border-base p-3 shadow-sm", children: [
425
+ /* @__PURE__ */ jsx(Text, { className: "text-xs font-medium text-ui-fg-base", children: "Traffic sources" }),
426
+ /* @__PURE__ */ jsxs(Text, { className: "mb-1 text-[10px] leading-snug text-ui-fg-muted", children: [
427
+ "Revenue share · ",
428
+ windowLabel
429
+ ] }),
430
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex h-[104px] items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : error ? /* @__PURE__ */ jsx("div", { className: "flex h-[104px] items-center justify-center px-1", children: /* @__PURE__ */ jsx(Text, { className: "text-center text-[10px] text-ui-fg-danger", children: error }) }) : traffic.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-[104px] items-center justify-center px-1", children: /* @__PURE__ */ jsx(Text, { className: "text-center text-[10px] leading-snug text-ui-fg-muted", children: "No traffic breakdown for this window." }) }) : totalRevenue <= 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-[104px] items-center justify-center px-1", children: /* @__PURE__ */ jsx(Text, { className: "text-center text-[10px] leading-snug text-ui-fg-muted", children: "No recorded revenue in this window." }) }) : /* @__PURE__ */ jsx(TrafficRevenueDonut, { traffic, compact: true }) })
431
+ ] });
432
+ }
330
433
  function AtlasKpiCard({
331
- index,
332
434
  label,
333
435
  value,
334
436
  helper,
335
437
  accent
336
438
  }) {
337
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-3 shadow-sm", children: [
439
+ const Icon = KPI_ICONS[accent];
440
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[112px] min-w-0 flex-col rounded-xl border border-ui-border-base/80 bg-ui-bg-subtle/25 p-4 shadow-sm", children: [
338
441
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
339
- /* @__PURE__ */ jsxs(Text, { className: "text-left text-[11px] leading-tight text-ui-fg-muted", children: [
340
- /* @__PURE__ */ jsxs("span", { className: "font-semibold text-ui-fg-base", children: [
341
- index,
342
- "."
343
- ] }),
344
- " ",
345
- label
346
- ] }),
442
+ /* @__PURE__ */ jsx(Text, { className: "min-w-0 flex-1 text-left text-xs font-medium leading-snug text-ui-fg-base", children: label }),
347
443
  /* @__PURE__ */ jsx(
348
444
  "div",
349
445
  {
350
- className: `h-7 w-7 shrink-0 rounded-full ${KPI_ICON_BG[accent]}`,
351
- "aria-hidden": true
446
+ className: `flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${KPI_ICON_BG[accent]}`,
447
+ "aria-hidden": true,
448
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-ui-fg-base" })
352
449
  }
353
450
  )
354
451
  ] }),
355
- /* @__PURE__ */ jsx("div", { className: "mt-2 text-base font-semibold tabular-nums tracking-tight text-ui-fg-base sm:text-lg", children: value }),
356
- helper ? /* @__PURE__ */ jsx(Text, { className: "mt-1 text-[10px] leading-snug text-ui-fg-muted", children: helper }) : null
452
+ /* @__PURE__ */ jsx("div", { className: "mt-3 text-xl font-semibold tabular-nums tracking-tight text-ui-fg-base sm:text-2xl", children: value }),
453
+ helper ? /* @__PURE__ */ jsx(Text, { className: "mt-2 text-[11px] leading-snug text-ui-fg-muted", children: helper }) : null
357
454
  ] });
358
455
  }
359
456
  const SUMMARY_PERIODS$1 = [
@@ -378,32 +475,33 @@ const STATUS_BAR_COLORS = {
378
475
  orders: "#38BDF8",
379
476
  revenue: "#D946EF"
380
477
  };
381
- const SELECT_CLASS_NAME = "h-8 min-w-[120px] rounded-lg border border-ui-border-strong bg-ui-bg-base px-2 text-xs text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive";
478
+ const CHART_AXIS_TICK = { fontSize: 10, fill: "#e5e7eb" };
479
+ const CHART_AXIS_TICK_SM = { fontSize: 9, fill: "#e5e7eb" };
480
+ const CHART_AXIS_LINE = "#94a3b8";
481
+ const SELECT_CLASS_NAME = "h-9 min-w-[132px] cursor-pointer appearance-none rounded-full border border-ui-border-base bg-ui-bg-base py-1.5 pl-3 pr-8 text-xs text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive";
382
482
  function EmptyAnalyticsPanel({
383
483
  title,
384
484
  description
385
485
  }) {
386
- return /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", className: "h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-[120px] flex-col justify-between gap-2 rounded-lg border border-dashed border-ui-border-base bg-ui-bg-subtle/40 p-3", children: [
387
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
388
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-xs font-semibold", children: title }),
389
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[11px] leading-snug", children: description })
390
- ] }),
391
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base/80 px-2.5 py-2", children: [
392
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Empty for now" }),
393
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base mt-0.5 text-[11px] leading-snug", children: "Reserved for live analytics when data is available." })
394
- ] })
395
- ] }) });
486
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-[88px] flex-col gap-1.5 rounded-lg border border-dashed border-ui-border-base px-3 py-3", children: [
487
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-xs font-semibold", children: title }),
488
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[11px] leading-snug", children: description })
489
+ ] });
396
490
  }
397
491
  function OrdersDashboard() {
398
- var _a, _b;
492
+ var _a, _b, _c, _d;
399
493
  const [data, setData] = useState(null);
400
494
  const [loading, setLoading] = useState(true);
401
495
  const [error, setError] = useState(null);
402
496
  const [filter, setFilter] = useState("all");
403
497
  const [dailyOrders, setDailyOrders] = useState([]);
498
+ const [previousPeriodDailyOrders, setPreviousPeriodDailyOrders] = useState([]);
404
499
  const [overTimePeriod, setOverTimePeriod] = useState("one_week");
405
500
  const [overTimeLoading, setOverTimeLoading] = useState(true);
406
501
  const [overTimeError, setOverTimeError] = useState(null);
502
+ const [ordersInsights, setOrdersInsights] = useState(null);
503
+ const [insightsLoading, setInsightsLoading] = useState(true);
504
+ const [insightsError, setInsightsError] = useState(null);
407
505
  const [todayContext, setTodayContext] = useState([]);
408
506
  const [todayContextLoading, setTodayContextLoading] = useState(true);
409
507
  const [todayContextError, setTodayContextError] = useState(null);
@@ -435,7 +533,10 @@ function OrdersDashboard() {
435
533
  if (!res.ok) throw new Error(res.statusText);
436
534
  return res.json();
437
535
  }).then((body) => {
438
- if (!cancelled) setDailyOrders(body.dailyOrders ?? []);
536
+ if (!cancelled) {
537
+ setDailyOrders(body.dailyOrders ?? []);
538
+ setPreviousPeriodDailyOrders(body.previousPeriodDailyOrders ?? []);
539
+ }
439
540
  }).catch((e) => {
440
541
  if (!cancelled) setOverTimeError(e instanceof Error ? e.message : String(e));
441
542
  }).finally(() => {
@@ -445,6 +546,31 @@ function OrdersDashboard() {
445
546
  cancelled = true;
446
547
  };
447
548
  }, [overTimePeriod]);
549
+ const insightsWindowDays = useMemo(() => {
550
+ if (overTimePeriod === "one_week") return 7;
551
+ if (overTimePeriod === "one_month") return 30;
552
+ return 365;
553
+ }, [overTimePeriod]);
554
+ useEffect(() => {
555
+ let cancelled = false;
556
+ setInsightsLoading(true);
557
+ setInsightsError(null);
558
+ fetch(`/admin/analytics/orders-insights?days=${insightsWindowDays}`, {
559
+ credentials: "include"
560
+ }).then((res) => {
561
+ if (!res.ok) throw new Error(res.statusText);
562
+ return res.json();
563
+ }).then((body) => {
564
+ if (!cancelled) setOrdersInsights(body);
565
+ }).catch((e) => {
566
+ if (!cancelled) setInsightsError(e instanceof Error ? e.message : String(e));
567
+ }).finally(() => {
568
+ if (!cancelled) setInsightsLoading(false);
569
+ });
570
+ return () => {
571
+ cancelled = true;
572
+ };
573
+ }, [insightsWindowDays]);
448
574
  useEffect(() => {
449
575
  let cancelled = false;
450
576
  setTodayContextLoading(true);
@@ -543,6 +669,86 @@ function OrdersDashboard() {
543
669
  const peakRevenuePoint = dailyOrders.length > 0 ? dailyOrders.reduce(
544
670
  (peak, point) => point.total_revenue > peak.total_revenue ? point : peak
545
671
  ) : null;
672
+ const previousPeriodRevenueTotal = useMemo(
673
+ () => previousPeriodDailyOrders.reduce((s, d) => s + d.total_revenue, 0),
674
+ [previousPeriodDailyOrders]
675
+ );
676
+ const previousPeriodOrdersTotal = useMemo(
677
+ () => previousPeriodDailyOrders.reduce((s, d) => s + d.orders_count, 0),
678
+ [previousPeriodDailyOrders]
679
+ );
680
+ const revenueVsPreviousPercent = previousPeriodRevenueTotal > 0 ? (trendRevenueTotal - previousPeriodRevenueTotal) / previousPeriodRevenueTotal * 100 : null;
681
+ const ordersVsPreviousPercent = previousPeriodOrdersTotal > 0 ? (trendOrdersTotal - previousPeriodOrdersTotal) / previousPeriodOrdersTotal * 100 : null;
682
+ const trendRowsDetailed = useMemo(() => {
683
+ return dailyOrders.map((d, i) => {
684
+ const prev = previousPeriodDailyOrders[i];
685
+ return {
686
+ ...d,
687
+ aov: bucketAov(d),
688
+ prev_revenue: (prev == null ? void 0 : prev.total_revenue) ?? 0,
689
+ prev_orders: (prev == null ? void 0 : prev.orders_count) ?? 0,
690
+ prev_aov: prev ? bucketAov(prev) : 0
691
+ };
692
+ });
693
+ }, [dailyOrders, previousPeriodDailyOrders]);
694
+ const hourlyChartRows = useMemo(() => {
695
+ if (!ordersInsights) return [];
696
+ return ordersInsights.byHour.map((h) => ({
697
+ label: `${String(h.hour).padStart(2, "0")}:00`,
698
+ hour: h.hour,
699
+ orders_count: h.orders_count,
700
+ revenue: h.revenue
701
+ }));
702
+ }, [ordersInsights]);
703
+ const weekdayChartRows = useMemo(() => {
704
+ if (!ordersInsights) return [];
705
+ return ordersInsights.byWeekday.map((w) => ({
706
+ label: w.label,
707
+ orders_count: w.orders_count,
708
+ revenue: w.revenue
709
+ }));
710
+ }, [ordersInsights]);
711
+ const ordersVsDraftsPie = useMemo(() => {
712
+ var _a2;
713
+ if (!ordersInsights) return [];
714
+ const placed = ((_a2 = ordersInsights.funnel[0]) == null ? void 0 : _a2.count) ?? 0;
715
+ const draftsCount = ordersInsights.drafts.available === true ? ordersInsights.drafts.count : 0;
716
+ return [
717
+ { name: "Orders placed (window)", value: placed, key: "placed" },
718
+ {
719
+ name: ordersInsights.drafts.available === true ? "Open draft orders (snapshot)" : "Draft orders (unavailable)",
720
+ value: draftsCount,
721
+ key: "drafts"
722
+ }
723
+ ];
724
+ }, [ordersInsights]);
725
+ const funnelTimeSeriesRows = useMemo(() => {
726
+ return dailyOrders.map((d) => {
727
+ const placed = d.orders_count;
728
+ const notCancelled = Math.max(0, d.orders_count - d.cancelled_count);
729
+ const shipped = d.shipped_count ?? 0;
730
+ const delivered = d.delivered_count;
731
+ const pctNotCancelled = placed > 0 ? notCancelled / placed * 100 : 0;
732
+ const pctShippedOfNc = notCancelled > 0 ? shipped / notCancelled * 100 : 0;
733
+ const pctDeliveredOfShipped = shipped > 0 ? delivered / shipped * 100 : 0;
734
+ return {
735
+ date: d.date,
736
+ label: d.label ?? formatChartLabel(d.date),
737
+ placed,
738
+ not_cancelled: notCancelled,
739
+ shipped,
740
+ delivered,
741
+ pct_not_cancelled: Math.round(pctNotCancelled * 10) / 10,
742
+ pct_shipped_of_active: Math.round(pctShippedOfNc * 10) / 10,
743
+ pct_delivered_of_shipped: Math.round(pctDeliveredOfShipped * 10) / 10
744
+ };
745
+ });
746
+ }, [dailyOrders]);
747
+ const trafficTotalRevenue = useMemo(
748
+ () => (ordersInsights == null ? void 0 : ordersInsights.traffic.reduce((sum, t) => sum + (t.revenue || 0), 0)) ?? 0,
749
+ [ordersInsights]
750
+ );
751
+ const insightsRangeLabel = ((_b = OVER_TIME_PERIODS.find((p) => p.value === overTimePeriod)) == null ? void 0 : _b.label) ?? "One week";
546
752
  const quickPulseMetrics = [
547
753
  {
548
754
  label: "Range revenue",
@@ -583,20 +789,22 @@ function OrdersDashboard() {
583
789
  if (error || !data) {
584
790
  return /* @__PURE__ */ jsx(Container, { className: "p-6", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger", children: error ?? "Failed to load analytics" }) });
585
791
  }
586
- return /* @__PURE__ */ jsx(AnalyticsDashboardShell, { children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base/70 bg-ui-bg-subtle/35 p-2 md:p-3", children: [
792
+ return /* @__PURE__ */ jsx(AnalyticsDashboardShell, { children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-2xl border border-ui-border-base/80 bg-ui-bg-base shadow-sm", children: [
587
793
  /* @__PURE__ */ jsx(
588
794
  AnalyticsDashboardHeader,
589
795
  {
590
796
  variant: "premium",
797
+ appearance: "inset",
798
+ actionsBare: true,
591
799
  title: "Orders",
592
800
  description: "Revenue, volume, and outcomes in a compact overview sized for a single viewport.",
593
- actions: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-2.5", children: [
594
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
801
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
802
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
595
803
  /* @__PURE__ */ jsx(
596
804
  Label,
597
805
  {
598
806
  htmlFor: "analytics-period",
599
- className: "text-ui-fg-muted text-xs font-medium",
807
+ className: "shrink-0 text-ui-fg-muted text-xs font-medium",
600
808
  children: "Period"
601
809
  }
602
810
  ),
@@ -611,7 +819,7 @@ function OrdersDashboard() {
611
819
  }
612
820
  )
613
821
  ] }),
614
- filter !== "all" && /* @__PURE__ */ jsx("div", { className: "flex items-center self-end pb-1", children: /* @__PURE__ */ jsx(
822
+ filter !== "all" ? /* @__PURE__ */ jsx(
615
823
  "button",
616
824
  {
617
825
  type: "button",
@@ -620,280 +828,1109 @@ function OrdersDashboard() {
620
828
  "aria-label": "Show all orders (clear filter)",
621
829
  children: "Clear period"
622
830
  }
623
- ) })
831
+ ) : null
624
832
  ] })
625
833
  }
626
834
  ),
627
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
628
- /* @__PURE__ */ jsx("div", { className: "px-0.5", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Order overview" }) }),
629
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-4", children: primaryStats.map((stat, index) => /* @__PURE__ */ jsx(
630
- AtlasKpiCard,
631
- {
632
- index: index + 1,
633
- label: stat.label,
634
- value: stat.value,
635
- helper: stat.helper,
636
- accent: stat.accent
637
- },
638
- stat.label
639
- )) })
640
- ] }),
641
- /* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-12 gap-3", children: [
642
- /* @__PURE__ */ jsx("div", { className: "col-span-12 xl:col-span-6", children: /* @__PURE__ */ jsx(
643
- AnalyticsSection,
644
- {
645
- variant: "atlas",
646
- title: "Revenue & orders",
647
- description: "Time series for the selected range. Window totals below match this chart.",
648
- actions: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
649
- /* @__PURE__ */ jsx(Label, { htmlFor: "over-time-period", className: "text-ui-fg-muted text-xs", children: "Range" }),
650
- /* @__PURE__ */ jsx(
651
- "select",
652
- {
653
- id: "over-time-period",
654
- value: overTimePeriod,
655
- onChange: (e) => setOverTimePeriod(e.target.value),
656
- className: SELECT_CLASS_NAME,
657
- children: OVER_TIME_PERIODS.map((p) => /* @__PURE__ */ jsx("option", { value: p.value, children: p.label }, p.value))
658
- }
659
- )
660
- ] }),
661
- children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
662
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-3", children: [
663
- /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
664
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window revenue" }),
665
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: formatCompactCurrency(trendRevenueTotal) }),
666
- /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-[10px]", children: [
667
- "Avg/day ",
668
- formatCompactCurrency(trendAverageRevenue)
669
- ] })
670
- ] }) }),
671
- /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
672
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window orders" }),
673
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: trendOrdersTotal.toLocaleString() }),
674
- /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-[10px]", children: [
675
- "Avg/day ",
676
- trendAverageOrders.toFixed(1)
677
- ] })
678
- ] }) }),
679
- /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
680
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Comparison" }),
681
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-sm font-semibold tracking-tight", children: "Last period" }),
682
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] leading-snug", children: "Reserved — API unchanged." })
683
- ] }) })
835
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3 p-3 pt-0 md:p-4 md:pt-0", children: [
836
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
837
+ /* @__PURE__ */ jsx("div", { className: "px-0.5", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Order overview" }) }),
838
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
839
+ /* @__PURE__ */ jsx(
840
+ TrafficSourcesOverviewCard,
841
+ {
842
+ traffic: (ordersInsights == null ? void 0 : ordersInsights.traffic) ?? [],
843
+ loading: insightsLoading,
844
+ error: insightsError,
845
+ totalRevenue: trafficTotalRevenue,
846
+ windowLabel: insightsRangeLabel
847
+ }
848
+ ),
849
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 lg:grid-cols-4", children: primaryStats.map((stat) => /* @__PURE__ */ jsx(
850
+ AtlasKpiCard,
851
+ {
852
+ label: stat.label,
853
+ value: stat.value,
854
+ helper: stat.helper,
855
+ accent: stat.accent
856
+ },
857
+ stat.label
858
+ )) })
859
+ ] })
860
+ ] }),
861
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-12 gap-2 xl:items-start", children: [
862
+ /* @__PURE__ */ jsx("div", { className: "col-span-12 xl:col-span-6", children: /* @__PURE__ */ jsx(
863
+ AnalyticsSection,
864
+ {
865
+ variant: "atlas",
866
+ actionsBare: true,
867
+ title: "Revenue & orders",
868
+ description: "Time series for the selected range. Window totals below match this chart.",
869
+ actions: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
870
+ /* @__PURE__ */ jsx(
871
+ Label,
872
+ {
873
+ htmlFor: "over-time-period",
874
+ className: "shrink-0 text-ui-fg-muted text-xs font-medium",
875
+ children: "Range"
876
+ }
877
+ ),
878
+ /* @__PURE__ */ jsx(
879
+ "select",
880
+ {
881
+ id: "over-time-period",
882
+ value: overTimePeriod,
883
+ onChange: (e) => setOverTimePeriod(e.target.value),
884
+ className: SELECT_CLASS_NAME,
885
+ children: OVER_TIME_PERIODS.map((p) => /* @__PURE__ */ jsx("option", { value: p.value, children: p.label }, p.value))
886
+ }
887
+ )
684
888
  ] }),
685
- /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", className: "relative overflow-hidden", children: [
686
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-6 top-0 h-12 rounded-b-full bg-gradient-to-r from-sky-400/10 via-fuchsia-400/10 to-transparent blur-xl" }),
687
- /* @__PURE__ */ jsxs("div", { className: "relative space-y-2", children: [
688
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
689
- /* @__PURE__ */ jsxs("div", { className: "space-y-0", children: [
690
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Trend overview" }),
691
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-sm font-semibold", children: ((_b = OVER_TIME_PERIODS.find((period) => period.value === overTimePeriod)) == null ? void 0 : _b.label) ?? "One week" })
889
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
890
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-1.5 sm:grid-cols-3", children: [
891
+ /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
892
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window revenue" }),
893
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: formatCompactCurrency(trendRevenueTotal) }),
894
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-[10px]", children: [
895
+ "Avg/day ",
896
+ formatCompactCurrency(trendAverageRevenue)
897
+ ] })
898
+ ] }) }),
899
+ /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
900
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window orders" }),
901
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: trendOrdersTotal.toLocaleString() }),
902
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-[10px]", children: [
903
+ "Avg/day ",
904
+ trendAverageOrders.toFixed(1)
905
+ ] })
906
+ ] }) }),
907
+ /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
908
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "vs previous period" }),
909
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: revenueVsPreviousPercent === null ? "—" : `${revenueVsPreviousPercent >= 0 ? "+" : ""}${revenueVsPreviousPercent.toFixed(1)}% rev` }),
910
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-[10px] leading-snug", children: [
911
+ "Orders",
912
+ " ",
913
+ ordersVsPreviousPercent === null ? "—" : `${ordersVsPreviousPercent >= 0 ? "+" : ""}${ordersVsPreviousPercent.toFixed(1)}%`
914
+ ] })
915
+ ] }) })
916
+ ] }),
917
+ !overTimeLoading && !overTimeError && dailyOrders.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
918
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-1.5 lg:grid-cols-3", children: [
919
+ /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
920
+ /* @__PURE__ */ jsx(Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Revenue over time" }),
921
+ /* @__PURE__ */ jsx("div", { className: "h-[118px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
922
+ LineChart,
923
+ {
924
+ data: trendRowsDetailed,
925
+ margin: { top: 4, right: 4, left: 0, bottom: 0 },
926
+ children: [
927
+ /* @__PURE__ */ jsx(
928
+ CartesianGrid,
929
+ {
930
+ strokeDasharray: "3 3",
931
+ vertical: false,
932
+ stroke: "rgba(148,163,184,0.12)"
933
+ }
934
+ ),
935
+ /* @__PURE__ */ jsx(XAxis, { dataKey: "date", hide: true }),
936
+ /* @__PURE__ */ jsx(
937
+ YAxis,
938
+ {
939
+ width: 36,
940
+ tick: CHART_AXIS_TICK_SM,
941
+ tickFormatter: (v) => formatCompactCurrency(Number(v))
942
+ }
943
+ ),
944
+ /* @__PURE__ */ jsx(
945
+ Tooltip,
946
+ {
947
+ content: ({ active, payload, label }) => {
948
+ var _a2, _b2, _c2, _d2;
949
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxs(
950
+ TooltipCard,
951
+ {
952
+ title: String(
953
+ isDailyOrderRow((_a2 = payload[0]) == null ? void 0 : _a2.payload) ? ((_b2 = payload[0]) == null ? void 0 : _b2.payload.label) ?? formatChartLabel(String(label)) : label
954
+ ),
955
+ children: [
956
+ /* @__PURE__ */ jsxs("div", { children: [
957
+ "This:",
958
+ " ",
959
+ /* @__PURE__ */ jsx("strong", { children: formatCompactCurrency(
960
+ Number(
961
+ (_c2 = payload.find((p) => p.dataKey === "total_revenue")) == null ? void 0 : _c2.value
962
+ ) || 0
963
+ ) })
964
+ ] }),
965
+ /* @__PURE__ */ jsxs("div", { children: [
966
+ "Previous:",
967
+ " ",
968
+ /* @__PURE__ */ jsx("strong", { children: formatCompactCurrency(
969
+ Number(
970
+ (_d2 = payload.find((p) => p.dataKey === "prev_revenue")) == null ? void 0 : _d2.value
971
+ ) || 0
972
+ ) })
973
+ ] })
974
+ ]
975
+ }
976
+ ) : null;
977
+ }
978
+ }
979
+ ),
980
+ /* @__PURE__ */ jsx(
981
+ Line,
982
+ {
983
+ type: "natural",
984
+ dataKey: "total_revenue",
985
+ name: "This period",
986
+ stroke: "#D946EF",
987
+ strokeWidth: 2,
988
+ dot: false
989
+ }
990
+ ),
991
+ /* @__PURE__ */ jsx(
992
+ Line,
993
+ {
994
+ type: "natural",
995
+ dataKey: "prev_revenue",
996
+ name: "Previous",
997
+ stroke: "#94a3b8",
998
+ strokeWidth: 1.5,
999
+ strokeDasharray: "5 4",
1000
+ dot: false
1001
+ }
1002
+ )
1003
+ ]
1004
+ }
1005
+ ) }) })
692
1006
  ] }),
693
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap justify-end gap-2 text-[10px] text-ui-fg-muted", children: [
694
- /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
695
- /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-sky-400" }),
696
- "Orders"
697
- ] }),
698
- /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
699
- /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-fuchsia-400" }),
700
- "Revenue"
701
- ] })
1007
+ /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1008
+ /* @__PURE__ */ jsx(Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Orders count" }),
1009
+ /* @__PURE__ */ jsx("div", { className: "h-[118px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1010
+ LineChart,
1011
+ {
1012
+ data: trendRowsDetailed,
1013
+ margin: { top: 4, right: 4, left: 0, bottom: 0 },
1014
+ children: [
1015
+ /* @__PURE__ */ jsx(
1016
+ CartesianGrid,
1017
+ {
1018
+ strokeDasharray: "3 3",
1019
+ vertical: false,
1020
+ stroke: "rgba(148,163,184,0.12)"
1021
+ }
1022
+ ),
1023
+ /* @__PURE__ */ jsx(XAxis, { dataKey: "date", hide: true }),
1024
+ /* @__PURE__ */ jsx(
1025
+ YAxis,
1026
+ {
1027
+ width: 28,
1028
+ tick: CHART_AXIS_TICK_SM,
1029
+ allowDecimals: false
1030
+ }
1031
+ ),
1032
+ /* @__PURE__ */ jsx(
1033
+ Tooltip,
1034
+ {
1035
+ content: ({ active, payload, label }) => {
1036
+ var _a2, _b2;
1037
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxs(TooltipCard, { title: String(label), children: [
1038
+ /* @__PURE__ */ jsxs("div", { children: [
1039
+ "This:",
1040
+ " ",
1041
+ /* @__PURE__ */ jsx("strong", { children: Math.floor(
1042
+ Number(
1043
+ (_a2 = payload.find((p) => p.dataKey === "orders_count")) == null ? void 0 : _a2.value
1044
+ ) || 0
1045
+ ).toLocaleString() })
1046
+ ] }),
1047
+ /* @__PURE__ */ jsxs("div", { children: [
1048
+ "Previous:",
1049
+ " ",
1050
+ /* @__PURE__ */ jsx("strong", { children: Math.floor(
1051
+ Number(
1052
+ (_b2 = payload.find((p) => p.dataKey === "prev_orders")) == null ? void 0 : _b2.value
1053
+ ) || 0
1054
+ ).toLocaleString() })
1055
+ ] })
1056
+ ] }) : null;
1057
+ }
1058
+ }
1059
+ ),
1060
+ /* @__PURE__ */ jsx(
1061
+ Line,
1062
+ {
1063
+ type: "natural",
1064
+ dataKey: "orders_count",
1065
+ name: "This period",
1066
+ stroke: "#38BDF8",
1067
+ strokeWidth: 2,
1068
+ dot: false
1069
+ }
1070
+ ),
1071
+ /* @__PURE__ */ jsx(
1072
+ Line,
1073
+ {
1074
+ type: "natural",
1075
+ dataKey: "prev_orders",
1076
+ name: "Previous",
1077
+ stroke: "#94a3b8",
1078
+ strokeWidth: 1.5,
1079
+ strokeDasharray: "5 4",
1080
+ dot: false
1081
+ }
1082
+ )
1083
+ ]
1084
+ }
1085
+ ) }) })
1086
+ ] }),
1087
+ /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1088
+ /* @__PURE__ */ jsx(Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "AOV (non-cancelled)" }),
1089
+ /* @__PURE__ */ jsx("div", { className: "h-[118px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1090
+ LineChart,
1091
+ {
1092
+ data: trendRowsDetailed,
1093
+ margin: { top: 4, right: 4, left: 0, bottom: 0 },
1094
+ children: [
1095
+ /* @__PURE__ */ jsx(
1096
+ CartesianGrid,
1097
+ {
1098
+ strokeDasharray: "3 3",
1099
+ vertical: false,
1100
+ stroke: "rgba(148,163,184,0.12)"
1101
+ }
1102
+ ),
1103
+ /* @__PURE__ */ jsx(XAxis, { dataKey: "date", hide: true }),
1104
+ /* @__PURE__ */ jsx(
1105
+ YAxis,
1106
+ {
1107
+ width: 36,
1108
+ tick: CHART_AXIS_TICK_SM,
1109
+ tickFormatter: (v) => formatCompactCurrency(Number(v))
1110
+ }
1111
+ ),
1112
+ /* @__PURE__ */ jsx(
1113
+ Tooltip,
1114
+ {
1115
+ content: ({ active, payload, label }) => {
1116
+ var _a2, _b2;
1117
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxs(TooltipCard, { title: String(label), children: [
1118
+ /* @__PURE__ */ jsxs("div", { children: [
1119
+ "This:",
1120
+ " ",
1121
+ /* @__PURE__ */ jsx("strong", { children: formatCurrency$1(
1122
+ Number(
1123
+ (_a2 = payload.find((p) => p.dataKey === "aov")) == null ? void 0 : _a2.value
1124
+ ) || 0
1125
+ ) })
1126
+ ] }),
1127
+ /* @__PURE__ */ jsxs("div", { children: [
1128
+ "Previous:",
1129
+ " ",
1130
+ /* @__PURE__ */ jsx("strong", { children: formatCurrency$1(
1131
+ Number(
1132
+ (_b2 = payload.find((p) => p.dataKey === "prev_aov")) == null ? void 0 : _b2.value
1133
+ ) || 0
1134
+ ) })
1135
+ ] })
1136
+ ] }) : null;
1137
+ }
1138
+ }
1139
+ ),
1140
+ /* @__PURE__ */ jsx(
1141
+ Line,
1142
+ {
1143
+ type: "natural",
1144
+ dataKey: "aov",
1145
+ name: "This period",
1146
+ stroke: "#D97706",
1147
+ strokeWidth: 2,
1148
+ dot: false
1149
+ }
1150
+ ),
1151
+ /* @__PURE__ */ jsx(
1152
+ Line,
1153
+ {
1154
+ type: "natural",
1155
+ dataKey: "prev_aov",
1156
+ name: "Previous",
1157
+ stroke: "#94a3b8",
1158
+ strokeWidth: 1.5,
1159
+ strokeDasharray: "5 4",
1160
+ dot: false
1161
+ }
1162
+ )
1163
+ ]
1164
+ }
1165
+ ) }) })
702
1166
  ] })
703
1167
  ] }),
704
- /* @__PURE__ */ jsx("div", { className: "h-[min(220px,32vh)] min-h-[180px] sm:h-[min(240px,34vh)]", children: overTimeLoading ? /* @__PURE__ */ jsx(
705
- "div",
706
- {
707
- className: "flex h-full items-center justify-center",
708
- role: "status",
709
- "aria-label": "Loading orders over time",
710
- children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading chart…" })
711
- }
712
- ) : overTimeError ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-xs", children: overTimeError }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
713
- ComposedChart,
714
- {
715
- data: dailyOrders,
716
- margin: { top: 4, right: 6, left: -6, bottom: 0 },
717
- children: [
718
- /* @__PURE__ */ jsxs("defs", { children: [
719
- /* @__PURE__ */ jsxs("linearGradient", { id: "ordersGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
720
- /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#67E8F9" }),
721
- /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#3B82F6" })
722
- ] }),
723
- /* @__PURE__ */ jsxs("linearGradient", { id: "revenueGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
724
- /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#F472B6" }),
725
- /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#C084FC" })
726
- ] }),
727
- /* @__PURE__ */ jsxs("linearGradient", { id: "ordersAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
728
- /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#38BDF8", stopOpacity: 0.22 }),
729
- /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#38BDF8", stopOpacity: 0 })
730
- ] }),
731
- /* @__PURE__ */ jsxs("linearGradient", { id: "revenueAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
732
- /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#E879F9", stopOpacity: 0.2 }),
733
- /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#E879F9", stopOpacity: 0 })
734
- ] })
1168
+ /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", className: "mt-1.5", children: [
1169
+ /* @__PURE__ */ jsx(Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Revenue breakdown (stacked — by order status)" }),
1170
+ /* @__PURE__ */ jsx("div", { className: "h-[min(168px,26vh)] min-h-[140px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1171
+ ComposedChart,
1172
+ {
1173
+ data: dailyOrders,
1174
+ margin: { top: 4, right: 8, left: -4, bottom: 0 },
1175
+ children: [
1176
+ /* @__PURE__ */ jsx(
1177
+ CartesianGrid,
1178
+ {
1179
+ stroke: "rgba(148,163,184,0.14)",
1180
+ strokeDasharray: "3 3",
1181
+ vertical: false
1182
+ }
1183
+ ),
1184
+ /* @__PURE__ */ jsx(
1185
+ XAxis,
1186
+ {
1187
+ dataKey: "date",
1188
+ tick: CHART_AXIS_TICK,
1189
+ tickLine: false,
1190
+ axisLine: false,
1191
+ tickFormatter: (value, index) => {
1192
+ const row = dailyOrders[index];
1193
+ return (row == null ? void 0 : row.label) ?? formatChartLabel(value);
1194
+ }
1195
+ }
1196
+ ),
1197
+ /* @__PURE__ */ jsx(
1198
+ YAxis,
1199
+ {
1200
+ tick: CHART_AXIS_TICK,
1201
+ tickFormatter: (v) => formatCompactCurrency(Number(v))
1202
+ }
1203
+ ),
1204
+ /* @__PURE__ */ jsx(
1205
+ Tooltip,
1206
+ {
1207
+ content: ({ active, payload, label }) => active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsx(TooltipCard, { title: String(label), children: payload.map((p) => /* @__PURE__ */ jsxs("div", { children: [
1208
+ p.name,
1209
+ ":",
1210
+ " ",
1211
+ /* @__PURE__ */ jsx("strong", { children: formatCurrency$1(Number(p.value) || 0) })
1212
+ ] }, String(p.name))) }) : null
1213
+ }
1214
+ ),
1215
+ /* @__PURE__ */ jsx(Legend, { wrapperStyle: { fontSize: 10 }, iconType: "circle" }),
1216
+ /* @__PURE__ */ jsx(
1217
+ Area,
1218
+ {
1219
+ type: "natural",
1220
+ dataKey: "revenue_delivered",
1221
+ name: "Delivered",
1222
+ stackId: "r",
1223
+ fill: "#10B981",
1224
+ stroke: "#059669",
1225
+ fillOpacity: 0.85
1226
+ }
1227
+ ),
1228
+ /* @__PURE__ */ jsx(
1229
+ Area,
1230
+ {
1231
+ type: "natural",
1232
+ dataKey: "revenue_open",
1233
+ name: "Open / pending",
1234
+ stackId: "r",
1235
+ fill: "#3B82F6",
1236
+ stroke: "#2563eb",
1237
+ fillOpacity: 0.85
1238
+ }
1239
+ ),
1240
+ /* @__PURE__ */ jsx(
1241
+ Area,
1242
+ {
1243
+ type: "natural",
1244
+ dataKey: "revenue_cancelled",
1245
+ name: "Cancelled",
1246
+ stackId: "r",
1247
+ fill: "#F87171",
1248
+ stroke: "#EF4444",
1249
+ fillOpacity: 0.75
1250
+ }
1251
+ )
1252
+ ]
1253
+ }
1254
+ ) }) })
1255
+ ] })
1256
+ ] }) : null,
1257
+ /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", className: "relative overflow-hidden", children: [
1258
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-6 top-0 h-12 rounded-b-full bg-gradient-to-r from-sky-400/10 via-fuchsia-400/10 to-transparent blur-xl" }),
1259
+ /* @__PURE__ */ jsxs("div", { className: "relative space-y-1", children: [
1260
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-1.5", children: [
1261
+ /* @__PURE__ */ jsxs("div", { className: "space-y-0", children: [
1262
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Trend overview" }),
1263
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-sm font-semibold", children: ((_c = OVER_TIME_PERIODS.find((period) => period.value === overTimePeriod)) == null ? void 0 : _c.label) ?? "One week" })
1264
+ ] }),
1265
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap justify-end gap-2 text-[10px] text-ui-fg-muted", children: [
1266
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
1267
+ /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-sky-400" }),
1268
+ "Orders"
735
1269
  ] }),
736
- /* @__PURE__ */ jsx(
737
- CartesianGrid,
738
- {
739
- stroke: "rgba(148,163,184,0.14)",
740
- strokeDasharray: "3 3",
741
- vertical: false
742
- }
743
- ),
744
- /* @__PURE__ */ jsx(
745
- XAxis,
746
- {
747
- dataKey: "date",
748
- tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
749
- tickLine: false,
750
- axisLine: false,
751
- tickFormatter: (value, index) => {
752
- const row = dailyOrders[index];
753
- return (row == null ? void 0 : row.label) ?? formatChartLabel(value);
1270
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
1271
+ /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-fuchsia-400" }),
1272
+ "Revenue"
1273
+ ] })
1274
+ ] })
1275
+ ] }),
1276
+ /* @__PURE__ */ jsx("div", { className: "h-[min(200px,30vh)] min-h-[160px] sm:h-[min(216px,32vh)]", children: overTimeLoading ? /* @__PURE__ */ jsx(
1277
+ "div",
1278
+ {
1279
+ className: "flex h-full items-center justify-center",
1280
+ role: "status",
1281
+ "aria-label": "Loading orders over time",
1282
+ children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading chart…" })
1283
+ }
1284
+ ) : overTimeError ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-xs", children: overTimeError }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1285
+ ComposedChart,
1286
+ {
1287
+ data: dailyOrders,
1288
+ margin: { top: 4, right: 6, left: -6, bottom: 0 },
1289
+ children: [
1290
+ /* @__PURE__ */ jsxs("defs", { children: [
1291
+ /* @__PURE__ */ jsxs("linearGradient", { id: "ordersGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
1292
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#67E8F9" }),
1293
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#3B82F6" })
1294
+ ] }),
1295
+ /* @__PURE__ */ jsxs("linearGradient", { id: "revenueGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
1296
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#F472B6" }),
1297
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#C084FC" })
1298
+ ] }),
1299
+ /* @__PURE__ */ jsxs("linearGradient", { id: "ordersAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1300
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#38BDF8", stopOpacity: 0.22 }),
1301
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#38BDF8", stopOpacity: 0 })
1302
+ ] }),
1303
+ /* @__PURE__ */ jsxs("linearGradient", { id: "revenueAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1304
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#E879F9", stopOpacity: 0.2 }),
1305
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#E879F9", stopOpacity: 0 })
1306
+ ] })
1307
+ ] }),
1308
+ /* @__PURE__ */ jsx(
1309
+ CartesianGrid,
1310
+ {
1311
+ stroke: "rgba(148,163,184,0.14)",
1312
+ strokeDasharray: "3 3",
1313
+ vertical: false
754
1314
  }
755
- }
756
- ),
757
- /* @__PURE__ */ jsx(
758
- YAxis,
759
- {
760
- yAxisId: "orders",
761
- width: 32,
762
- tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
763
- tickLine: false,
764
- axisLine: false,
765
- allowDecimals: false,
766
- tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
767
- }
768
- ),
769
- /* @__PURE__ */ jsx(
770
- YAxis,
771
- {
772
- yAxisId: "revenue",
773
- orientation: "right",
774
- width: 40,
775
- tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
776
- tickLine: false,
777
- axisLine: false,
778
- tickFormatter: (value) => formatCompactCurrency(Number(value) || 0)
779
- }
780
- ),
781
- /* @__PURE__ */ jsx(
782
- Tooltip,
783
- {
784
- content: /* @__PURE__ */ jsx(OrdersTrendTooltip, {}),
785
- cursor: {
786
- stroke: "rgba(248, 250, 252, 0.35)",
787
- strokeWidth: 1
1315
+ ),
1316
+ /* @__PURE__ */ jsx(
1317
+ XAxis,
1318
+ {
1319
+ dataKey: "date",
1320
+ tick: CHART_AXIS_TICK,
1321
+ tickLine: false,
1322
+ axisLine: false,
1323
+ tickFormatter: (value, index) => {
1324
+ const row = dailyOrders[index];
1325
+ return (row == null ? void 0 : row.label) ?? formatChartLabel(value);
1326
+ }
788
1327
  }
789
- }
790
- ),
791
- /* @__PURE__ */ jsx(
792
- Legend,
793
- {
794
- wrapperStyle: { fontSize: 10, paddingTop: 2 },
795
- iconType: "circle",
796
- iconSize: 8
797
- }
798
- ),
799
- /* @__PURE__ */ jsx(
800
- Area,
801
- {
802
- yAxisId: "orders",
803
- type: "natural",
804
- dataKey: "orders_count",
805
- stroke: "none",
806
- fill: "url(#ordersAreaFill)",
807
- isAnimationActive: false
808
- }
809
- ),
810
- /* @__PURE__ */ jsx(
811
- Area,
812
- {
813
- yAxisId: "revenue",
814
- type: "natural",
815
- dataKey: "total_revenue",
816
- stroke: "none",
817
- fill: "url(#revenueAreaFill)",
818
- isAnimationActive: false
819
- }
820
- ),
821
- /* @__PURE__ */ jsx(
822
- Line,
823
- {
824
- yAxisId: "orders",
825
- type: "natural",
826
- dataKey: "orders_count",
827
- name: "Orders",
828
- stroke: "url(#ordersGradient)",
829
- strokeWidth: 2,
830
- dot: false,
831
- activeDot: { r: 4, fill: STATUS_BAR_COLORS.orders }
832
- }
833
- ),
834
- /* @__PURE__ */ jsx(
835
- Line,
836
- {
837
- yAxisId: "revenue",
838
- type: "natural",
839
- dataKey: "total_revenue",
840
- name: "Revenue",
841
- stroke: "url(#revenueGradient)",
842
- strokeWidth: 2,
843
- dot: false,
844
- activeDot: { r: 4, fill: STATUS_BAR_COLORS.revenue }
845
- }
846
- )
847
- ]
848
- }
849
- ) }) })
1328
+ ),
1329
+ /* @__PURE__ */ jsx(
1330
+ YAxis,
1331
+ {
1332
+ yAxisId: "orders",
1333
+ width: 32,
1334
+ tick: CHART_AXIS_TICK,
1335
+ tickLine: false,
1336
+ axisLine: false,
1337
+ allowDecimals: false,
1338
+ tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
1339
+ }
1340
+ ),
1341
+ /* @__PURE__ */ jsx(
1342
+ YAxis,
1343
+ {
1344
+ yAxisId: "revenue",
1345
+ orientation: "right",
1346
+ width: 40,
1347
+ tick: CHART_AXIS_TICK,
1348
+ tickLine: false,
1349
+ axisLine: false,
1350
+ tickFormatter: (value) => formatCompactCurrency(Number(value) || 0)
1351
+ }
1352
+ ),
1353
+ /* @__PURE__ */ jsx(
1354
+ Tooltip,
1355
+ {
1356
+ content: /* @__PURE__ */ jsx(OrdersTrendTooltip, {}),
1357
+ cursor: {
1358
+ stroke: "rgba(248, 250, 252, 0.35)",
1359
+ strokeWidth: 1
1360
+ }
1361
+ }
1362
+ ),
1363
+ /* @__PURE__ */ jsx(
1364
+ Area,
1365
+ {
1366
+ yAxisId: "orders",
1367
+ type: "natural",
1368
+ dataKey: "orders_count",
1369
+ stroke: "none",
1370
+ fill: "url(#ordersAreaFill)",
1371
+ isAnimationActive: false,
1372
+ legendType: "none"
1373
+ }
1374
+ ),
1375
+ /* @__PURE__ */ jsx(
1376
+ Area,
1377
+ {
1378
+ yAxisId: "revenue",
1379
+ type: "natural",
1380
+ dataKey: "total_revenue",
1381
+ stroke: "none",
1382
+ fill: "url(#revenueAreaFill)",
1383
+ isAnimationActive: false,
1384
+ legendType: "none"
1385
+ }
1386
+ ),
1387
+ /* @__PURE__ */ jsx(
1388
+ Line,
1389
+ {
1390
+ yAxisId: "orders",
1391
+ type: "natural",
1392
+ dataKey: "orders_count",
1393
+ name: "Orders",
1394
+ stroke: "url(#ordersGradient)",
1395
+ strokeWidth: 2,
1396
+ dot: false,
1397
+ activeDot: { r: 4, fill: STATUS_BAR_COLORS.orders }
1398
+ }
1399
+ ),
1400
+ /* @__PURE__ */ jsx(
1401
+ Line,
1402
+ {
1403
+ yAxisId: "revenue",
1404
+ type: "natural",
1405
+ dataKey: "total_revenue",
1406
+ name: "Revenue",
1407
+ stroke: "url(#revenueGradient)",
1408
+ strokeWidth: 2,
1409
+ dot: false,
1410
+ activeDot: { r: 4, fill: STATUS_BAR_COLORS.revenue }
1411
+ }
1412
+ )
1413
+ ]
1414
+ }
1415
+ ) }) })
1416
+ ] })
850
1417
  ] })
851
1418
  ] })
852
- ] })
853
- }
854
- ) }),
855
- /* @__PURE__ */ jsx("div", { className: "col-span-12 flex flex-col gap-3 xl:col-span-3", children: /* @__PURE__ */ jsxs(
856
- AnalyticsSection,
857
- {
858
- variant: "atlas",
859
- title: "Pulse & range",
860
- description: "Window totals and an orders time series for the selected range.",
861
- children: [
862
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: quickPulseMetrics.map((metric) => /* @__PURE__ */ jsxs(
863
- "div",
1419
+ }
1420
+ ) }),
1421
+ /* @__PURE__ */ jsxs("div", { className: "col-span-12 flex flex-col gap-2 xl:col-span-6", children: [
1422
+ /* @__PURE__ */ jsxs(
1423
+ AnalyticsSection,
1424
+ {
1425
+ variant: "atlas",
1426
+ title: "Pulse & range",
1427
+ description: "Window totals and an orders time series for the selected range.",
1428
+ children: [
1429
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: quickPulseMetrics.map((metric) => /* @__PURE__ */ jsxs(
1430
+ "div",
1431
+ {
1432
+ className: `rounded-lg border border-ui-border-base bg-ui-bg-base px-2 py-2 shadow-sm ${metric.accentClassName}`.trim(),
1433
+ children: [
1434
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: metric.label }),
1435
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base mt-0.5 text-sm font-semibold tracking-tight", children: metric.value }),
1436
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted mt-0.5 text-[9px] leading-snug", children: metric.helper })
1437
+ ]
1438
+ },
1439
+ metric.label
1440
+ )) }),
1441
+ !overTimeLoading && !overTimeError && dailyOrders.length > 0 ? /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", className: "mt-1.5", children: [
1442
+ /* @__PURE__ */ jsx(Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Orders (time series)" }),
1443
+ /* @__PURE__ */ jsx("div", { className: "h-[76px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1444
+ LineChart,
1445
+ {
1446
+ data: dailyOrders,
1447
+ margin: { top: 2, right: 4, left: -18, bottom: 2 },
1448
+ children: [
1449
+ /* @__PURE__ */ jsx(
1450
+ CartesianGrid,
1451
+ {
1452
+ strokeDasharray: "3 3",
1453
+ vertical: false,
1454
+ stroke: "rgba(148,163,184,0.12)"
1455
+ }
1456
+ ),
1457
+ /* @__PURE__ */ jsx(XAxis, { dataKey: "date", hide: true }),
1458
+ /* @__PURE__ */ jsx(YAxis, { hide: true, domain: ["auto", "auto"] }),
1459
+ /* @__PURE__ */ jsx(
1460
+ Tooltip,
1461
+ {
1462
+ content: /* @__PURE__ */ jsx(OrdersSparklineTooltip, {}),
1463
+ cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 }
1464
+ }
1465
+ ),
1466
+ /* @__PURE__ */ jsx(
1467
+ Line,
1468
+ {
1469
+ type: "natural",
1470
+ dataKey: "orders_count",
1471
+ stroke: "#3b82f6",
1472
+ strokeWidth: 2,
1473
+ dot: { r: 2, fill: "#3b82f6" },
1474
+ activeDot: { r: 3 }
1475
+ }
1476
+ )
1477
+ ]
1478
+ }
1479
+ ) }) })
1480
+ ] }) : null
1481
+ ]
1482
+ }
1483
+ ),
1484
+ /* @__PURE__ */ jsx(
1485
+ AnalyticsSection,
1486
+ {
1487
+ variant: "atlas",
1488
+ title: "Order → fulfillment funnel",
1489
+ description: `Stages by order created date (UTC), same range as Revenue & orders (${((_d = OVER_TIME_PERIODS.find((p) => p.value === overTimePeriod)) == null ? void 0 : _d.label) ?? "period"}). Not storefront visitors.`,
1490
+ children: overTimeLoading ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[120px] items-center justify-center py-3", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : overTimeError ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[120px] items-center justify-center px-2 py-3", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-center text-xs", children: overTimeError }) }) }) : funnelTimeSeriesRows.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
1491
+ /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1492
+ /* @__PURE__ */ jsx(Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Stage counts (time series)" }),
1493
+ /* @__PURE__ */ jsx("div", { className: "h-[min(200px,30vh)] min-h-[168px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1494
+ LineChart,
1495
+ {
1496
+ data: funnelTimeSeriesRows,
1497
+ margin: { top: 4, right: 8, left: 0, bottom: 4 },
1498
+ children: [
1499
+ /* @__PURE__ */ jsx(
1500
+ CartesianGrid,
1501
+ {
1502
+ strokeDasharray: "3 3",
1503
+ stroke: "rgba(148,163,184,0.2)"
1504
+ }
1505
+ ),
1506
+ /* @__PURE__ */ jsx(
1507
+ XAxis,
1508
+ {
1509
+ dataKey: "date",
1510
+ tick: CHART_AXIS_TICK_SM,
1511
+ stroke: CHART_AXIS_LINE,
1512
+ tickLine: { stroke: CHART_AXIS_LINE },
1513
+ tickFormatter: (value) => {
1514
+ const row = dailyOrders.find((r) => r.date === value);
1515
+ return (row == null ? void 0 : row.label) ?? formatChartLabel(String(value));
1516
+ }
1517
+ }
1518
+ ),
1519
+ /* @__PURE__ */ jsx(
1520
+ YAxis,
1521
+ {
1522
+ tick: CHART_AXIS_TICK_SM,
1523
+ stroke: CHART_AXIS_LINE,
1524
+ tickLine: { stroke: CHART_AXIS_LINE },
1525
+ width: 28,
1526
+ allowDecimals: false,
1527
+ tickFormatter: (v) => Math.floor(Number(v) || 0).toLocaleString()
1528
+ }
1529
+ ),
1530
+ /* @__PURE__ */ jsx(
1531
+ Tooltip,
1532
+ {
1533
+ content: ({ active, payload, label }) => {
1534
+ var _a2;
1535
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsx(
1536
+ TooltipCard,
1537
+ {
1538
+ title: typeof label === "string" ? ((_a2 = dailyOrders.find((r) => r.date === label)) == null ? void 0 : _a2.label) ?? formatChartLabel(label) : String(label),
1539
+ children: payload.map((p) => /* @__PURE__ */ jsxs("div", { children: [
1540
+ String(p.name),
1541
+ ":",
1542
+ " ",
1543
+ /* @__PURE__ */ jsx("strong", { children: Math.floor(Number(p.value) || 0).toLocaleString() })
1544
+ ] }, String(p.dataKey)))
1545
+ }
1546
+ ) : null;
1547
+ }
1548
+ }
1549
+ ),
1550
+ /* @__PURE__ */ jsx(
1551
+ Legend,
1552
+ {
1553
+ wrapperStyle: { fontSize: 9, color: "#e5e7eb", paddingTop: 4 },
1554
+ iconType: "circle",
1555
+ iconSize: 6
1556
+ }
1557
+ ),
1558
+ /* @__PURE__ */ jsx(
1559
+ Line,
1560
+ {
1561
+ type: "natural",
1562
+ dataKey: "placed",
1563
+ name: "Placed",
1564
+ stroke: "#6366F1",
1565
+ strokeWidth: 2,
1566
+ dot: false
1567
+ }
1568
+ ),
1569
+ /* @__PURE__ */ jsx(
1570
+ Line,
1571
+ {
1572
+ type: "natural",
1573
+ dataKey: "not_cancelled",
1574
+ name: "Not cancelled",
1575
+ stroke: "#22d3ee",
1576
+ strokeWidth: 2,
1577
+ dot: false
1578
+ }
1579
+ ),
1580
+ /* @__PURE__ */ jsx(
1581
+ Line,
1582
+ {
1583
+ type: "natural",
1584
+ dataKey: "shipped",
1585
+ name: "Shipped",
1586
+ stroke: "#F59E0B",
1587
+ strokeWidth: 2,
1588
+ dot: false
1589
+ }
1590
+ ),
1591
+ /* @__PURE__ */ jsx(
1592
+ Line,
1593
+ {
1594
+ type: "natural",
1595
+ dataKey: "delivered",
1596
+ name: "Delivered",
1597
+ stroke: "#10B981",
1598
+ strokeWidth: 2,
1599
+ dot: false
1600
+ }
1601
+ )
1602
+ ]
1603
+ }
1604
+ ) }) })
1605
+ ] }),
1606
+ /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1607
+ /* @__PURE__ */ jsx(Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Stage conversion (% of prior stage, same buckets)" }),
1608
+ /* @__PURE__ */ jsx("div", { className: "h-[min(168px,26vh)] min-h-[140px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1609
+ LineChart,
1610
+ {
1611
+ data: funnelTimeSeriesRows,
1612
+ margin: { top: 4, right: 8, left: 0, bottom: 4 },
1613
+ children: [
1614
+ /* @__PURE__ */ jsx(
1615
+ CartesianGrid,
1616
+ {
1617
+ strokeDasharray: "3 3",
1618
+ stroke: "rgba(148,163,184,0.2)"
1619
+ }
1620
+ ),
1621
+ /* @__PURE__ */ jsx(
1622
+ XAxis,
1623
+ {
1624
+ dataKey: "date",
1625
+ tick: CHART_AXIS_TICK_SM,
1626
+ stroke: CHART_AXIS_LINE,
1627
+ tickLine: { stroke: CHART_AXIS_LINE },
1628
+ tickFormatter: (value) => {
1629
+ const row = dailyOrders.find((r) => r.date === value);
1630
+ return (row == null ? void 0 : row.label) ?? formatChartLabel(String(value));
1631
+ }
1632
+ }
1633
+ ),
1634
+ /* @__PURE__ */ jsx(
1635
+ YAxis,
1636
+ {
1637
+ domain: [0, 100],
1638
+ tick: CHART_AXIS_TICK_SM,
1639
+ stroke: CHART_AXIS_LINE,
1640
+ tickLine: { stroke: CHART_AXIS_LINE },
1641
+ width: 36,
1642
+ tickFormatter: (v) => `${Math.round(Number(v) || 0)}%`
1643
+ }
1644
+ ),
1645
+ /* @__PURE__ */ jsx(
1646
+ Tooltip,
1647
+ {
1648
+ content: ({ active, payload, label }) => {
1649
+ var _a2;
1650
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsx(
1651
+ TooltipCard,
1652
+ {
1653
+ title: typeof label === "string" ? ((_a2 = dailyOrders.find((r) => r.date === label)) == null ? void 0 : _a2.label) ?? formatChartLabel(label) : String(label),
1654
+ children: payload.map((p) => /* @__PURE__ */ jsxs("div", { children: [
1655
+ String(p.name),
1656
+ ":",
1657
+ " ",
1658
+ /* @__PURE__ */ jsx("strong", { children: formatPercent(Number(p.value) || 0) })
1659
+ ] }, String(p.dataKey)))
1660
+ }
1661
+ ) : null;
1662
+ }
1663
+ }
1664
+ ),
1665
+ /* @__PURE__ */ jsx(
1666
+ Legend,
1667
+ {
1668
+ wrapperStyle: { fontSize: 9, color: "#e5e7eb", paddingTop: 4 },
1669
+ iconType: "circle",
1670
+ iconSize: 6
1671
+ }
1672
+ ),
1673
+ /* @__PURE__ */ jsx(
1674
+ Line,
1675
+ {
1676
+ type: "natural",
1677
+ dataKey: "pct_not_cancelled",
1678
+ name: "Not cancelled / placed",
1679
+ stroke: "#6366F1",
1680
+ strokeWidth: 2,
1681
+ dot: false
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ jsx(
1685
+ Line,
1686
+ {
1687
+ type: "natural",
1688
+ dataKey: "pct_shipped_of_active",
1689
+ name: "Shipped / not cancelled",
1690
+ stroke: "#F59E0B",
1691
+ strokeWidth: 2,
1692
+ dot: false
1693
+ }
1694
+ ),
1695
+ /* @__PURE__ */ jsx(
1696
+ Line,
1697
+ {
1698
+ type: "natural",
1699
+ dataKey: "pct_delivered_of_shipped",
1700
+ name: "Delivered / shipped",
1701
+ stroke: "#10B981",
1702
+ strokeWidth: 2,
1703
+ dot: false
1704
+ }
1705
+ )
1706
+ ]
1707
+ }
1708
+ ) }) })
1709
+ ] })
1710
+ ] }) : /* @__PURE__ */ jsx(
1711
+ EmptyAnalyticsPanel,
1712
+ {
1713
+ title: "No funnel data",
1714
+ description: "No orders in this range to chart."
1715
+ }
1716
+ )
1717
+ }
1718
+ ),
1719
+ /* @__PURE__ */ jsx(
1720
+ AnalyticsSection,
1721
+ {
1722
+ variant: "atlas",
1723
+ title: "Order revenue (attribution)",
1724
+ description: "All revenue is from captured Medusa orders until storefront channel data exists.",
1725
+ children: insightsLoading ? /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center py-3", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : insightsError ? /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-3", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) : ordersInsights && ordersInsights.traffic.length > 0 ? trafficTotalRevenue <= 0 ? /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted px-0.5 text-center text-[11px] leading-snug", children: "No recorded revenue in this window (totals may be zero until orders are paid or finalized)." }) : /* @__PURE__ */ jsx(TrafficRevenueDonut, { traffic: ordersInsights.traffic }) : /* @__PURE__ */ jsx(
1726
+ EmptyAnalyticsPanel,
1727
+ {
1728
+ title: "No order revenue",
1729
+ description: "No orders in this window."
1730
+ }
1731
+ )
1732
+ }
1733
+ )
1734
+ ] })
1735
+ ] }),
1736
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-1.5", children: [
1737
+ /* @__PURE__ */ jsx("div", { className: "px-0.5", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Operational signals" }) }),
1738
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-3 xl:grid-cols-6", children: secondaryStats.map((stat) => /* @__PURE__ */ jsx(
1739
+ AnalyticsStatCard,
1740
+ {
1741
+ label: stat.label,
1742
+ value: stat.value,
1743
+ helper: stat.helper,
1744
+ variant: "compact"
1745
+ },
1746
+ stat.label
1747
+ )) })
1748
+ ] }),
1749
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-2 xl:grid-cols-12", children: [
1750
+ /* @__PURE__ */ jsx(
1751
+ AnalyticsSection,
1752
+ {
1753
+ variant: "atlas",
1754
+ className: "xl:col-span-7",
1755
+ title: "Order outcomes",
1756
+ description: "Delivered, cancelled, exchanges, and returns per bucket — same window as Revenue & orders.",
1757
+ children: /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "h-[176px] sm:h-[196px]", children: overTimeLoading ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : overTimeError ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-xs", children: overTimeError }) }) : !outcomesTimeSeriesHasPoints ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "No outcome events in this range." }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1758
+ LineChart,
864
1759
  {
865
- className: `rounded-lg border border-ui-border-base bg-ui-bg-base px-2 py-2 shadow-sm ${metric.accentClassName}`.trim(),
1760
+ data: dailyOrders,
1761
+ margin: { top: 4, right: 8, left: 0, bottom: 0 },
866
1762
  children: [
867
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: metric.label }),
868
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base mt-0.5 text-sm font-semibold tracking-tight", children: metric.value }),
869
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted mt-0.5 text-[9px] leading-snug", children: metric.helper })
1763
+ /* @__PURE__ */ jsx(
1764
+ CartesianGrid,
1765
+ {
1766
+ stroke: "rgba(148,163,184,0.14)",
1767
+ strokeDasharray: "3 3",
1768
+ vertical: false
1769
+ }
1770
+ ),
1771
+ /* @__PURE__ */ jsx(
1772
+ XAxis,
1773
+ {
1774
+ dataKey: "date",
1775
+ tick: CHART_AXIS_TICK,
1776
+ tickLine: false,
1777
+ axisLine: false,
1778
+ tickFormatter: (value) => {
1779
+ const dateStr = typeof value === "string" ? value : String(value);
1780
+ const row = dailyOrders.find((d) => d.date === dateStr);
1781
+ return (row == null ? void 0 : row.label) ?? formatChartLabel(dateStr);
1782
+ }
1783
+ }
1784
+ ),
1785
+ /* @__PURE__ */ jsx(
1786
+ YAxis,
1787
+ {
1788
+ width: 28,
1789
+ tick: CHART_AXIS_TICK,
1790
+ tickLine: false,
1791
+ axisLine: false,
1792
+ allowDecimals: false,
1793
+ tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
1794
+ }
1795
+ ),
1796
+ /* @__PURE__ */ jsx(
1797
+ Tooltip,
1798
+ {
1799
+ content: /* @__PURE__ */ jsx(OutcomesTrendTooltip, {}),
1800
+ cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 }
1801
+ }
1802
+ ),
1803
+ /* @__PURE__ */ jsx(
1804
+ Legend,
1805
+ {
1806
+ wrapperStyle: { fontSize: 9, paddingTop: 0 },
1807
+ iconType: "circle",
1808
+ iconSize: 6
1809
+ }
1810
+ ),
1811
+ /* @__PURE__ */ jsx(
1812
+ Line,
1813
+ {
1814
+ type: "natural",
1815
+ dataKey: "delivered_count",
1816
+ name: "Delivered",
1817
+ stroke: STATUS_BAR_COLORS.delivered,
1818
+ strokeWidth: 2,
1819
+ dot: false
1820
+ }
1821
+ ),
1822
+ /* @__PURE__ */ jsx(
1823
+ Line,
1824
+ {
1825
+ type: "natural",
1826
+ dataKey: "cancelled_count",
1827
+ name: "Cancelled",
1828
+ stroke: STATUS_BAR_COLORS.cancelled,
1829
+ strokeWidth: 2,
1830
+ dot: false
1831
+ }
1832
+ ),
1833
+ /* @__PURE__ */ jsx(
1834
+ Line,
1835
+ {
1836
+ type: "natural",
1837
+ dataKey: "exchange_count",
1838
+ name: "Exchanges",
1839
+ stroke: STATUS_BAR_COLORS.exchange,
1840
+ strokeWidth: 2,
1841
+ dot: false
1842
+ }
1843
+ ),
1844
+ /* @__PURE__ */ jsx(
1845
+ Line,
1846
+ {
1847
+ type: "natural",
1848
+ dataKey: "return_count",
1849
+ name: "Returns",
1850
+ stroke: STATUS_BAR_COLORS.return,
1851
+ strokeWidth: 2,
1852
+ dot: false
1853
+ }
1854
+ )
870
1855
  ]
871
- },
872
- metric.label
873
- )) }),
874
- !overTimeLoading && !overTimeError && dailyOrders.length > 0 ? /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", className: "mt-2", children: [
875
- /* @__PURE__ */ jsx(Text, { className: "mb-1 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Orders (time series)" }),
876
- /* @__PURE__ */ jsx("div", { className: "h-[88px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
877
- LineChart,
1856
+ }
1857
+ ) }) }) })
1858
+ }
1859
+ ),
1860
+ /* @__PURE__ */ jsx(
1861
+ AnalyticsSection,
1862
+ {
1863
+ variant: "atlas",
1864
+ className: "xl:col-span-5",
1865
+ title: "Recent orders (7 days)",
1866
+ description: "Daily order count vs 7-day average — time series.",
1867
+ children: /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1868
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-1.5", children: [
1869
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 px-2 py-2", children: [
1870
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Today" }),
1871
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-base font-semibold tracking-tight", children: (todayPoint == null ? void 0 : todayPoint.orders_count.toLocaleString()) ?? "0" })
1872
+ ] }),
1873
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 px-2 py-2", children: [
1874
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "7-day avg" }),
1875
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-base font-semibold tracking-tight", children: todayOrdersAverage.toFixed(1) })
1876
+ ] })
1877
+ ] }),
1878
+ /* @__PURE__ */ jsx("div", { className: "h-[140px] sm:h-[156px]", children: todayContextLoading ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : todayContextError ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-xs", children: todayContextError }) }) : todayChartData.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "No recent activity." }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1879
+ ComposedChart,
878
1880
  {
879
- data: dailyOrders,
880
- margin: { top: 2, right: 4, left: -18, bottom: 2 },
1881
+ data: todayChartData,
1882
+ margin: { top: 4, right: 4, left: -4, bottom: 0 },
881
1883
  children: [
1884
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "todayOrdersFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1885
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#3b82f6", stopOpacity: 0.2 }),
1886
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#3b82f6", stopOpacity: 0 })
1887
+ ] }) }),
1888
+ /* @__PURE__ */ jsx(
1889
+ CartesianGrid,
1890
+ {
1891
+ stroke: "rgba(148,163,184,0.14)",
1892
+ strokeDasharray: "3 3",
1893
+ vertical: false
1894
+ }
1895
+ ),
1896
+ /* @__PURE__ */ jsx(
1897
+ XAxis,
1898
+ {
1899
+ dataKey: "date",
1900
+ tick: CHART_AXIS_TICK,
1901
+ tickLine: false,
1902
+ axisLine: false,
1903
+ tickFormatter: formatChartLabel
1904
+ }
1905
+ ),
1906
+ /* @__PURE__ */ jsx(
1907
+ YAxis,
1908
+ {
1909
+ width: 28,
1910
+ tick: CHART_AXIS_TICK,
1911
+ tickLine: false,
1912
+ axisLine: false,
1913
+ allowDecimals: false,
1914
+ tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
1915
+ }
1916
+ ),
1917
+ /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(OrdersTodayTooltip, {}), cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 } }),
882
1918
  /* @__PURE__ */ jsx(
883
- CartesianGrid,
1919
+ ReferenceLine,
884
1920
  {
885
- strokeDasharray: "3 3",
886
- vertical: false,
887
- stroke: "rgba(148,163,184,0.12)"
1921
+ y: todayOrdersAverage,
1922
+ stroke: "rgba(148,163,184,0.65)",
1923
+ strokeDasharray: "4 4"
888
1924
  }
889
1925
  ),
890
- /* @__PURE__ */ jsx(XAxis, { dataKey: "date", hide: true }),
891
- /* @__PURE__ */ jsx(YAxis, { hide: true, domain: ["auto", "auto"] }),
892
1926
  /* @__PURE__ */ jsx(
893
- Tooltip,
1927
+ Area,
894
1928
  {
895
- content: /* @__PURE__ */ jsx(OrdersSparklineTooltip, {}),
896
- cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 }
1929
+ type: "natural",
1930
+ dataKey: "orders_count",
1931
+ stroke: "none",
1932
+ fill: "url(#todayOrdersFill)",
1933
+ isAnimationActive: false
897
1934
  }
898
1935
  ),
899
1936
  /* @__PURE__ */ jsx(
@@ -901,31 +1938,111 @@ function OrdersDashboard() {
901
1938
  {
902
1939
  type: "natural",
903
1940
  dataKey: "orders_count",
1941
+ name: "Orders",
904
1942
  stroke: "#3b82f6",
905
1943
  strokeWidth: 2,
906
- dot: { r: 2, fill: "#3b82f6" },
907
- activeDot: { r: 3 }
1944
+ dot: (props) => {
1945
+ const { cx, cy, payload } = props;
1946
+ if (payload && typeof payload === "object" && "isToday" in payload && payload.isToday) {
1947
+ return /* @__PURE__ */ jsx(
1948
+ "circle",
1949
+ {
1950
+ cx,
1951
+ cy,
1952
+ r: 4,
1953
+ fill: STATUS_BAR_COLORS.today,
1954
+ stroke: "var(--medusa-color-ui-bg-base)",
1955
+ strokeWidth: 1
1956
+ }
1957
+ );
1958
+ }
1959
+ return /* @__PURE__ */ jsx("circle", { cx, cy, r: 0, fill: "transparent" });
1960
+ }
908
1961
  }
909
1962
  )
910
1963
  ]
911
1964
  }
912
- ) }) })
913
- ] }) : null
914
- ]
915
- }
916
- ) }),
917
- /* @__PURE__ */ jsxs("div", { className: "col-span-12 flex flex-col gap-3 xl:col-span-3", children: [
1965
+ ) }) }),
1966
+ /* @__PURE__ */ jsxs(Container, { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/40 px-2 py-1.5 shadow-sm", children: [
1967
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Note" }),
1968
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-[11px] leading-snug", children: todayDelta === null ? "Compares the latest day to the 7-day mean." : todayDelta >= 0 ? `Latest day is ${todayDelta.toFixed(1)} above the 7-day average.` : `Latest day is ${Math.abs(todayDelta).toFixed(1)} below the 7-day average.` })
1969
+ ] })
1970
+ ] }) })
1971
+ }
1972
+ )
1973
+ ] }),
1974
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-2 md:grid-cols-3", children: [
918
1975
  /* @__PURE__ */ jsx(
919
1976
  AnalyticsSection,
920
1977
  {
921
1978
  variant: "atlas",
922
- title: "Conversion funnel",
923
- description: "Storefront funnel connect events to enable this chart.",
924
- children: /* @__PURE__ */ jsx(
1979
+ title: "Sales by weekday",
1980
+ description: `Order revenue by UTC weekday last ${insightsWindowDays} days.`,
1981
+ children: insightsLoading ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : insightsError ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) }) : weekdayChartRows.length > 0 ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "h-[min(176px,28vh)] min-h-[148px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1982
+ BarChart,
1983
+ {
1984
+ data: weekdayChartRows,
1985
+ margin: { top: 2, right: 4, left: -8, bottom: 2 },
1986
+ children: [
1987
+ /* @__PURE__ */ jsx(
1988
+ CartesianGrid,
1989
+ {
1990
+ strokeDasharray: "3 3",
1991
+ vertical: false,
1992
+ stroke: "rgba(148,163,184,0.12)"
1993
+ }
1994
+ ),
1995
+ /* @__PURE__ */ jsx(
1996
+ XAxis,
1997
+ {
1998
+ dataKey: "label",
1999
+ tick: CHART_AXIS_TICK
2000
+ }
2001
+ ),
2002
+ /* @__PURE__ */ jsx(
2003
+ YAxis,
2004
+ {
2005
+ width: 40,
2006
+ tick: CHART_AXIS_TICK_SM,
2007
+ tickFormatter: (v) => formatCompactCurrency(Number(v))
2008
+ }
2009
+ ),
2010
+ /* @__PURE__ */ jsx(
2011
+ Tooltip,
2012
+ {
2013
+ content: ({ active, payload, label }) => {
2014
+ var _a2, _b2;
2015
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxs(TooltipCard, { title: String(label), children: [
2016
+ /* @__PURE__ */ jsxs("div", { children: [
2017
+ "Revenue:",
2018
+ " ",
2019
+ /* @__PURE__ */ jsx("strong", { children: formatCurrency$1(
2020
+ Number(
2021
+ (_a2 = payload.find((p) => p.dataKey === "revenue")) == null ? void 0 : _a2.value
2022
+ ) || 0
2023
+ ) })
2024
+ ] }),
2025
+ /* @__PURE__ */ jsxs("div", { children: [
2026
+ "Orders:",
2027
+ " ",
2028
+ /* @__PURE__ */ jsx("strong", { children: Math.floor(
2029
+ Number(
2030
+ (_b2 = payload.find((p) => p.dataKey === "orders_count")) == null ? void 0 : _b2.value
2031
+ ) || 0
2032
+ ).toLocaleString() })
2033
+ ] })
2034
+ ] }) : null;
2035
+ }
2036
+ }
2037
+ ),
2038
+ /* @__PURE__ */ jsx(Bar, { dataKey: "revenue", name: "Revenue", fill: "#D946EF", radius: [4, 4, 0, 0] })
2039
+ ]
2040
+ }
2041
+ ) }) }) }) : /* @__PURE__ */ jsx(
925
2042
  EmptyAnalyticsPanel,
926
2043
  {
927
- title: "Visitors to purchase funnel",
928
- description: "Visitor, product view, cart, checkout, and purchase steps require storefront analytics."
2044
+ title: "No weekday data",
2045
+ description: "No orders in this window."
929
2046
  }
930
2047
  )
931
2048
  }
@@ -934,303 +2051,142 @@ function OrdersDashboard() {
934
2051
  AnalyticsSection,
935
2052
  {
936
2053
  variant: "atlas",
937
- title: "Traffic sources",
938
- description: "Attribution mix when marketing data is available.",
939
- children: /* @__PURE__ */ jsx(
940
- EmptyAnalyticsPanel,
941
- {
942
- title: "Source mix",
943
- description: "Channel breakdown (direct, search, social, email) will appear here once connected."
944
- }
945
- )
946
- }
947
- )
948
- ] })
949
- ] }),
950
- /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-1.5", children: [
951
- /* @__PURE__ */ jsx("div", { className: "px-0.5", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Operational signals" }) }),
952
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-3 xl:grid-cols-6", children: secondaryStats.map((stat) => /* @__PURE__ */ jsx(
953
- AnalyticsStatCard,
954
- {
955
- label: stat.label,
956
- value: stat.value,
957
- helper: stat.helper,
958
- variant: "compact"
959
- },
960
- stat.label
961
- )) })
962
- ] }),
963
- /* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-3 xl:grid-cols-12", children: [
964
- /* @__PURE__ */ jsx(
965
- AnalyticsSection,
966
- {
967
- variant: "atlas",
968
- className: "xl:col-span-7",
969
- title: "Order outcomes",
970
- description: "Delivered, cancelled, exchanges, and returns per bucket — same window as Revenue & orders.",
971
- children: /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "h-[200px] sm:h-[220px]", children: overTimeLoading ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : overTimeError ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-xs", children: overTimeError }) }) : !outcomesTimeSeriesHasPoints ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "No outcome events in this range." }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
972
- LineChart,
973
- {
974
- data: dailyOrders,
975
- margin: { top: 4, right: 8, left: 0, bottom: 0 },
976
- children: [
977
- /* @__PURE__ */ jsx(
978
- CartesianGrid,
979
- {
980
- stroke: "rgba(148,163,184,0.14)",
981
- strokeDasharray: "3 3",
982
- vertical: false
983
- }
984
- ),
985
- /* @__PURE__ */ jsx(
986
- XAxis,
987
- {
988
- dataKey: "date",
989
- tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
990
- tickLine: false,
991
- axisLine: false,
992
- tickFormatter: (value) => {
993
- const dateStr = typeof value === "string" ? value : String(value);
994
- const row = dailyOrders.find((d) => d.date === dateStr);
995
- return (row == null ? void 0 : row.label) ?? formatChartLabel(dateStr);
996
- }
997
- }
998
- ),
2054
+ title: "Placed orders vs drafts",
2055
+ description: "Window order count vs current open draft orders (admin). Not storefront cart abandonment.",
2056
+ children: insightsLoading ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : insightsError ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) }) : ordersVsDraftsPie.some((s) => s.value > 0) ? /* @__PURE__ */ jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
2057
+ /* @__PURE__ */ jsx("div", { className: "h-[min(176px,28vh)] min-h-[148px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { margin: { top: 2, bottom: 2, left: 2, right: 2 }, children: [
999
2058
  /* @__PURE__ */ jsx(
1000
- YAxis,
2059
+ Pie,
1001
2060
  {
1002
- width: 28,
1003
- tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
1004
- tickLine: false,
1005
- axisLine: false,
1006
- allowDecimals: false,
1007
- tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
2061
+ data: ordersVsDraftsPie,
2062
+ dataKey: "value",
2063
+ nameKey: "name",
2064
+ cx: "50%",
2065
+ cy: "46%",
2066
+ innerRadius: 40,
2067
+ outerRadius: 58,
2068
+ paddingAngle: 2,
2069
+ children: ordersVsDraftsPie.map((slice, i) => /* @__PURE__ */ jsx(
2070
+ Cell,
2071
+ {
2072
+ fill: PIE_PALETTE[i % PIE_PALETTE.length]
2073
+ },
2074
+ slice.key
2075
+ ))
1008
2076
  }
1009
2077
  ),
1010
2078
  /* @__PURE__ */ jsx(
1011
2079
  Tooltip,
1012
2080
  {
1013
- content: /* @__PURE__ */ jsx(OutcomesTrendTooltip, {}),
1014
- cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 }
2081
+ content: ({ active, payload }) => {
2082
+ var _a2, _b2;
2083
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsx(TooltipCard, { title: String(((_a2 = payload[0]) == null ? void 0 : _a2.name) ?? ""), children: /* @__PURE__ */ jsxs("div", { children: [
2084
+ "Count:",
2085
+ " ",
2086
+ /* @__PURE__ */ jsx("strong", { children: Math.floor(
2087
+ Number((_b2 = payload[0]) == null ? void 0 : _b2.value) || 0
2088
+ ).toLocaleString() })
2089
+ ] }) }) : null;
2090
+ }
1015
2091
  }
1016
2092
  ),
1017
2093
  /* @__PURE__ */ jsx(
1018
2094
  Legend,
1019
2095
  {
1020
2096
  wrapperStyle: { fontSize: 9, paddingTop: 0 },
1021
- iconType: "circle",
1022
- iconSize: 6
1023
- }
1024
- ),
1025
- /* @__PURE__ */ jsx(
1026
- Line,
1027
- {
1028
- type: "natural",
1029
- dataKey: "delivered_count",
1030
- name: "Delivered",
1031
- stroke: STATUS_BAR_COLORS.delivered,
1032
- strokeWidth: 2,
1033
- dot: false
1034
- }
1035
- ),
1036
- /* @__PURE__ */ jsx(
1037
- Line,
1038
- {
1039
- type: "natural",
1040
- dataKey: "cancelled_count",
1041
- name: "Cancelled",
1042
- stroke: STATUS_BAR_COLORS.cancelled,
1043
- strokeWidth: 2,
1044
- dot: false
1045
- }
1046
- ),
1047
- /* @__PURE__ */ jsx(
1048
- Line,
1049
- {
1050
- type: "natural",
1051
- dataKey: "exchange_count",
1052
- name: "Exchanges",
1053
- stroke: STATUS_BAR_COLORS.exchange,
1054
- strokeWidth: 2,
1055
- dot: false
1056
- }
1057
- ),
1058
- /* @__PURE__ */ jsx(
1059
- Line,
1060
- {
1061
- type: "natural",
1062
- dataKey: "return_count",
1063
- name: "Returns",
1064
- stroke: STATUS_BAR_COLORS.return,
1065
- strokeWidth: 2,
1066
- dot: false
2097
+ verticalAlign: "bottom",
2098
+ height: 22,
2099
+ iconType: "circle"
1067
2100
  }
1068
2101
  )
1069
- ]
1070
- }
1071
- ) }) }) })
1072
- }
1073
- ),
1074
- /* @__PURE__ */ jsx(
1075
- AnalyticsSection,
1076
- {
1077
- variant: "atlas",
1078
- className: "xl:col-span-5",
1079
- title: "Recent orders (7 days)",
1080
- description: "Daily order count vs 7-day average — time series.",
1081
- children: /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1082
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1083
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 px-2 py-2", children: [
1084
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Today" }),
1085
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-base font-semibold tracking-tight", children: (todayPoint == null ? void 0 : todayPoint.orders_count.toLocaleString()) ?? "0" })
1086
- ] }),
1087
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 px-2 py-2", children: [
1088
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "7-day avg" }),
1089
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-base font-semibold tracking-tight", children: todayOrdersAverage.toFixed(1) })
1090
- ] })
1091
- ] }),
1092
- /* @__PURE__ */ jsx("div", { className: "h-[160px] sm:h-[180px]", children: todayContextLoading ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : todayContextError ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-xs", children: todayContextError }) }) : todayChartData.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "No recent activity." }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
1093
- ComposedChart,
2102
+ ] }) }) }),
2103
+ (ordersInsights == null ? void 0 : ordersInsights.drafts.available) === false ? /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted mt-0.5 px-0.5 text-[10px] leading-snug", children: "Draft totals need draft_order remote query access." }) : null
2104
+ ] }) : /* @__PURE__ */ jsx(
2105
+ EmptyAnalyticsPanel,
2106
+ {
2107
+ title: "Nothing to compare",
2108
+ description: "No placed orders and no draft rows in this snapshot."
2109
+ }
2110
+ )
2111
+ }
2112
+ ),
2113
+ /* @__PURE__ */ jsx(
2114
+ AnalyticsSection,
2115
+ {
2116
+ variant: "atlas",
2117
+ title: "Sales by hour (UTC)",
2118
+ description: `Orders created by hour last ${insightsWindowDays} days.`,
2119
+ children: insightsLoading ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : insightsError ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) }) : hourlyChartRows.length > 0 ? /* @__PURE__ */ jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsx("div", { className: "h-[min(176px,28vh)] min-h-[148px] w-full", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
2120
+ BarChart,
1094
2121
  {
1095
- data: todayChartData,
1096
- margin: { top: 4, right: 4, left: -4, bottom: 0 },
2122
+ data: hourlyChartRows,
2123
+ margin: { top: 2, right: 4, left: -8, bottom: 2 },
1097
2124
  children: [
1098
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "todayOrdersFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1099
- /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#3b82f6", stopOpacity: 0.2 }),
1100
- /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#3b82f6", stopOpacity: 0 })
1101
- ] }) }),
1102
2125
  /* @__PURE__ */ jsx(
1103
2126
  CartesianGrid,
1104
2127
  {
1105
- stroke: "rgba(148,163,184,0.14)",
1106
2128
  strokeDasharray: "3 3",
1107
- vertical: false
2129
+ vertical: false,
2130
+ stroke: "rgba(148,163,184,0.12)"
1108
2131
  }
1109
2132
  ),
1110
2133
  /* @__PURE__ */ jsx(
1111
2134
  XAxis,
1112
2135
  {
1113
- dataKey: "date",
1114
- tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
1115
- tickLine: false,
1116
- axisLine: false,
1117
- tickFormatter: formatChartLabel
2136
+ dataKey: "label",
2137
+ interval: 3,
2138
+ tick: CHART_AXIS_TICK_SM
1118
2139
  }
1119
2140
  ),
1120
2141
  /* @__PURE__ */ jsx(
1121
2142
  YAxis,
1122
2143
  {
1123
2144
  width: 28,
1124
- tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
1125
- tickLine: false,
1126
- axisLine: false,
1127
- allowDecimals: false,
1128
- tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
1129
- }
1130
- ),
1131
- /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(OrdersTodayTooltip, {}), cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 } }),
1132
- /* @__PURE__ */ jsx(
1133
- ReferenceLine,
1134
- {
1135
- y: todayOrdersAverage,
1136
- stroke: "rgba(148,163,184,0.65)",
1137
- strokeDasharray: "4 4"
1138
- }
1139
- ),
1140
- /* @__PURE__ */ jsx(
1141
- Area,
1142
- {
1143
- type: "natural",
1144
- dataKey: "orders_count",
1145
- stroke: "none",
1146
- fill: "url(#todayOrdersFill)",
1147
- isAnimationActive: false
2145
+ tick: CHART_AXIS_TICK,
2146
+ allowDecimals: false
1148
2147
  }
1149
2148
  ),
1150
2149
  /* @__PURE__ */ jsx(
1151
- Line,
2150
+ Tooltip,
1152
2151
  {
1153
- type: "natural",
1154
- dataKey: "orders_count",
1155
- name: "Orders",
1156
- stroke: "#3b82f6",
1157
- strokeWidth: 2,
1158
- dot: (props) => {
1159
- const { cx, cy, payload } = props;
1160
- if (payload && typeof payload === "object" && "isToday" in payload && payload.isToday) {
1161
- return /* @__PURE__ */ jsx(
1162
- "circle",
1163
- {
1164
- cx,
1165
- cy,
1166
- r: 4,
1167
- fill: STATUS_BAR_COLORS.today,
1168
- stroke: "var(--medusa-color-ui-bg-base)",
1169
- strokeWidth: 1
1170
- }
1171
- );
1172
- }
1173
- return /* @__PURE__ */ jsx("circle", { cx, cy, r: 0, fill: "transparent" });
2152
+ content: ({ active, payload, label }) => {
2153
+ var _a2, _b2;
2154
+ return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxs(TooltipCard, { title: String(label), children: [
2155
+ /* @__PURE__ */ jsxs("div", { children: [
2156
+ "Orders:",
2157
+ " ",
2158
+ /* @__PURE__ */ jsx("strong", { children: Math.floor(
2159
+ Number(
2160
+ (_a2 = payload.find((p) => p.dataKey === "orders_count")) == null ? void 0 : _a2.value
2161
+ ) || 0
2162
+ ).toLocaleString() })
2163
+ ] }),
2164
+ /* @__PURE__ */ jsxs("div", { children: [
2165
+ "Revenue:",
2166
+ " ",
2167
+ /* @__PURE__ */ jsx("strong", { children: formatCurrency$1(
2168
+ Number(
2169
+ (_b2 = payload.find((p) => p.dataKey === "revenue")) == null ? void 0 : _b2.value
2170
+ ) || 0
2171
+ ) })
2172
+ ] })
2173
+ ] }) : null;
1174
2174
  }
1175
2175
  }
1176
- )
2176
+ ),
2177
+ /* @__PURE__ */ jsx(Bar, { dataKey: "orders_count", name: "Orders", fill: "#38BDF8", radius: [4, 4, 0, 0] })
1177
2178
  ]
1178
2179
  }
1179
- ) }) }),
1180
- /* @__PURE__ */ jsxs(Container, { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/40 px-2.5 py-2 shadow-sm", children: [
1181
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Note" }),
1182
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-base text-[11px] leading-snug", children: todayDelta === null ? "Compares the latest day to the 7-day mean." : todayDelta >= 0 ? `Latest day is ${todayDelta.toFixed(1)} above the 7-day average.` : `Latest day is ${Math.abs(todayDelta).toFixed(1)} below the 7-day average.` })
1183
- ] })
1184
- ] }) })
1185
- }
1186
- )
1187
- ] }),
1188
- /* @__PURE__ */ jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-3 md:grid-cols-3", children: [
1189
- /* @__PURE__ */ jsx(
1190
- AnalyticsSection,
1191
- {
1192
- variant: "atlas",
1193
- title: "Revenue breakdown",
1194
- description: "Category or source contribution — time series when connected.",
1195
- children: /* @__PURE__ */ jsx(
1196
- EmptyAnalyticsPanel,
1197
- {
1198
- title: "Stacked breakdown",
1199
- description: "Connect product or attribution dimensions to show stacked area over time."
1200
- }
1201
- )
1202
- }
1203
- ),
1204
- /* @__PURE__ */ jsx(
1205
- AnalyticsSection,
1206
- {
1207
- variant: "atlas",
1208
- title: "Cart abandonment",
1209
- description: "Converted vs abandoned — time series when cart analytics exist.",
1210
- children: /* @__PURE__ */ jsx(
1211
- EmptyAnalyticsPanel,
1212
- {
1213
- title: "Checkout leakage",
1214
- description: "Donut and trend charts will use cart lifecycle data once available."
1215
- }
1216
- )
1217
- }
1218
- ),
1219
- /* @__PURE__ */ jsx(
1220
- AnalyticsSection,
1221
- {
1222
- variant: "atlas",
1223
- title: "Sales by time",
1224
- description: "Hourly or intraday patterns — bar time series when connected.",
1225
- children: /* @__PURE__ */ jsx(
1226
- EmptyAnalyticsPanel,
1227
- {
1228
- title: "Sales by hour",
1229
- description: "Order timestamps by hour-of-day will render as a compact bar time series."
1230
- }
1231
- )
1232
- }
1233
- )
2180
+ ) }) }) }) : /* @__PURE__ */ jsx(
2181
+ EmptyAnalyticsPanel,
2182
+ {
2183
+ title: "No hourly data",
2184
+ description: "No orders in this window."
2185
+ }
2186
+ )
2187
+ }
2188
+ )
2189
+ ] })
1234
2190
  ] })
1235
2191
  ] }) });
1236
2192
  }
@@ -1272,6 +2228,17 @@ function CustomersOverTimeTooltip({
1272
2228
  }
1273
2229
  );
1274
2230
  }
2231
+ function MixPieTooltip({
2232
+ active,
2233
+ payload
2234
+ }) {
2235
+ if (!active || !(payload == null ? void 0 : payload.length)) return null;
2236
+ const row = payload[0];
2237
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm shadow-md", children: [
2238
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-base", children: row.name }),
2239
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: Math.floor(Number(row.value) || 0).toLocaleString() })
2240
+ ] });
2241
+ }
1275
2242
  const COUNT_DAY_PRESETS = [
1276
2243
  { value: "all", label: "All time" },
1277
2244
  { value: "0", label: "Today" },
@@ -1295,12 +2262,15 @@ function CustomersDashboard() {
1295
2262
  const [graphPeriod, setGraphPeriod] = useState("one_week");
1296
2263
  const [graphLoading, setGraphLoading] = useState(true);
1297
2264
  const [graphError, setGraphError] = useState(null);
2265
+ const [repeatStats, setRepeatStats] = useState(null);
2266
+ const [repeatLoading, setRepeatLoading] = useState(true);
2267
+ const [repeatError, setRepeatError] = useState(null);
1298
2268
  useEffect(() => {
1299
2269
  let cancelled = false;
1300
2270
  setLoading(true);
1301
2271
  setError(null);
1302
2272
  const url = `/admin/analytics/customers-summary?days=${countDays}`;
1303
- fetch(url).then((res) => {
2273
+ fetch(url, { credentials: "include" }).then((res) => {
1304
2274
  if (!res.ok) throw new Error(res.statusText);
1305
2275
  return res.json();
1306
2276
  }).then((body) => {
@@ -1319,7 +2289,7 @@ function CustomersDashboard() {
1319
2289
  setGraphLoading(true);
1320
2290
  setGraphError(null);
1321
2291
  const url = `/admin/analytics/customers-over-time?period=${graphPeriod}`;
1322
- fetch(url).then((res) => {
2292
+ fetch(url, { credentials: "include" }).then((res) => {
1323
2293
  if (!res.ok) throw new Error(res.statusText);
1324
2294
  return res.json();
1325
2295
  }).then((body) => {
@@ -1333,6 +2303,34 @@ function CustomersDashboard() {
1333
2303
  cancelled = true;
1334
2304
  };
1335
2305
  }, [graphPeriod]);
2306
+ useEffect(() => {
2307
+ let cancelled = false;
2308
+ setRepeatLoading(true);
2309
+ setRepeatError(null);
2310
+ fetch(`/admin/analytics/repeat-customers?days=${countDays}`, {
2311
+ credentials: "include"
2312
+ }).then((res) => {
2313
+ if (!res.ok) throw new Error(res.statusText);
2314
+ return res.json();
2315
+ }).then((body) => {
2316
+ if (!cancelled) setRepeatStats(body);
2317
+ }).catch((e) => {
2318
+ if (!cancelled) setRepeatError(e instanceof Error ? e.message : String(e));
2319
+ }).finally(() => {
2320
+ if (!cancelled) setRepeatLoading(false);
2321
+ });
2322
+ return () => {
2323
+ cancelled = true;
2324
+ };
2325
+ }, [countDays]);
2326
+ const guestRegisteredPieData = useMemo(() => {
2327
+ const g = Math.max(0, Math.floor((data == null ? void 0 : data.guestCount) ?? 0));
2328
+ const r = Math.max(0, Math.floor((data == null ? void 0 : data.registeredCount) ?? 0));
2329
+ return [
2330
+ { name: "Guest checkout", value: g, key: "guest" },
2331
+ { name: "Registered", value: r, key: "registered" }
2332
+ ].filter((s) => s.value > 0);
2333
+ }, [data]);
1336
2334
  if (loading) {
1337
2335
  return /* @__PURE__ */ jsx(
1338
2336
  "div",
@@ -1417,6 +2415,70 @@ function CustomersDashboard() {
1417
2415
  }
1418
2416
  )
1419
2417
  ] }),
2418
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-2", children: [
2419
+ /* @__PURE__ */ jsx(
2420
+ AnalyticsSection,
2421
+ {
2422
+ title: "Guest vs registered",
2423
+ description: "Customer mix for the selected count period (same filter as the summary cards).",
2424
+ children: /* @__PURE__ */ jsx(AnalyticsChartSurface, { children: /* @__PURE__ */ jsx("div", { className: "h-72", children: guestRegisteredPieData.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "No guest or registered customers in this range." }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { children: [
2425
+ /* @__PURE__ */ jsx(
2426
+ Pie,
2427
+ {
2428
+ data: guestRegisteredPieData,
2429
+ dataKey: "value",
2430
+ nameKey: "name",
2431
+ cx: "50%",
2432
+ cy: "50%",
2433
+ innerRadius: 52,
2434
+ outerRadius: 88,
2435
+ paddingAngle: 2,
2436
+ children: guestRegisteredPieData.map((entry) => /* @__PURE__ */ jsx(
2437
+ Cell,
2438
+ {
2439
+ fill: entry.key === "guest" ? GUEST_COLOR : REGISTERED_COLOR
2440
+ },
2441
+ entry.key
2442
+ ))
2443
+ }
2444
+ ),
2445
+ /* @__PURE__ */ jsx(Tooltip, { content: /* @__PURE__ */ jsx(MixPieTooltip, {}) }),
2446
+ /* @__PURE__ */ jsx(Legend, { wrapperStyle: { fontSize: 12 }, iconType: "circle" })
2447
+ ] }) }) }) })
2448
+ }
2449
+ ),
2450
+ /* @__PURE__ */ jsx(
2451
+ AnalyticsSection,
2452
+ {
2453
+ title: "Repeat purchases",
2454
+ description: "Orders with a customer_id in the same window as the period filter (guest checkouts excluded from rate).",
2455
+ children: /* @__PURE__ */ jsx(AnalyticsChartSurface, { children: repeatLoading ? /* @__PURE__ */ jsx("div", { className: "flex min-h-[200px] items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "Loading…" }) }) : repeatError ? /* @__PURE__ */ jsx("div", { className: "flex min-h-[200px] items-center justify-center px-2", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger text-center text-sm", children: repeatError }) }) : repeatStats ? /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", children: [
2456
+ /* @__PURE__ */ jsx(
2457
+ AnalyticsStatCard,
2458
+ {
2459
+ label: "Repeat rate",
2460
+ value: `${repeatStats.repeat_rate_percent.toFixed(1)}%`,
2461
+ helper: repeatStats.window_days >= 365 ? "Approx. 12-month window" : `Last ${repeatStats.window_days} days`
2462
+ }
2463
+ ),
2464
+ /* @__PURE__ */ jsx(
2465
+ AnalyticsStatCard,
2466
+ {
2467
+ label: "Customers with orders",
2468
+ value: repeatStats.customers_with_orders.toLocaleString()
2469
+ }
2470
+ ),
2471
+ /* @__PURE__ */ jsx(
2472
+ AnalyticsStatCard,
2473
+ {
2474
+ label: "Repeat customers (2+)",
2475
+ value: repeatStats.repeat_customers.toLocaleString()
2476
+ }
2477
+ )
2478
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex min-h-[200px] items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "No data." }) }) })
2479
+ }
2480
+ )
2481
+ ] }),
1420
2482
  /* @__PURE__ */ jsx(
1421
2483
  AnalyticsSection,
1422
2484
  {
@@ -1808,6 +2870,10 @@ function ProductsDashboard() {
1808
2870
  })).reverse(),
1809
2871
  [performance]
1810
2872
  );
2873
+ const viewsVsUnitsScatterData = useMemo(
2874
+ () => ((performance == null ? void 0 : performance.topViewedProducts) ?? []).slice(0, 48).filter((row) => row.total_views > 0 || row.units_sold > 0),
2875
+ [performance]
2876
+ );
1811
2877
  if (summaryLoading) {
1812
2878
  return /* @__PURE__ */ jsx(
1813
2879
  "div",
@@ -2153,7 +3219,66 @@ function ProductsDashboard() {
2153
3219
  ] }) })
2154
3220
  }
2155
3221
  )
2156
- ] })
3222
+ ] }),
3223
+ /* @__PURE__ */ jsx(
3224
+ AnalyticsSection,
3225
+ {
3226
+ title: "Views vs units sold",
3227
+ description: "Each point is a product (top viewed in this period). Requires product view tracking.",
3228
+ children: /* @__PURE__ */ jsx(AnalyticsChartSurface, { children: /* @__PURE__ */ jsx("div", { className: "h-80", children: performanceLoading ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "Loading scatter…" }) }) : performanceError || !performance ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger", children: performanceError ?? "Failed to load product performance" }) }) : !performance.productViewsConnected ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "Product view tracking is not available in this environment." }) }) : viewsVsUnitsScatterData.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "No products with views or sales in this range." }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(ScatterChart, { margin: { top: 12, right: 16, bottom: 8, left: 8 }, children: [
3229
+ /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "rgba(148,163,184,0.2)" }),
3230
+ /* @__PURE__ */ jsx(
3231
+ XAxis,
3232
+ {
3233
+ type: "number",
3234
+ dataKey: "total_views",
3235
+ name: "Views",
3236
+ tick: { fontSize: 11 },
3237
+ allowDecimals: false,
3238
+ label: {
3239
+ value: "Views",
3240
+ position: "insideBottom",
3241
+ offset: -4,
3242
+ fontSize: 11,
3243
+ fill: "#6b7280"
3244
+ }
3245
+ }
3246
+ ),
3247
+ /* @__PURE__ */ jsx(
3248
+ YAxis,
3249
+ {
3250
+ type: "number",
3251
+ dataKey: "units_sold",
3252
+ name: "Units sold",
3253
+ tick: { fontSize: 11 },
3254
+ allowDecimals: false,
3255
+ label: {
3256
+ value: "Units sold",
3257
+ angle: -90,
3258
+ position: "insideLeft",
3259
+ fontSize: 11,
3260
+ fill: "#6b7280"
3261
+ }
3262
+ }
3263
+ ),
3264
+ /* @__PURE__ */ jsx(
3265
+ Tooltip,
3266
+ {
3267
+ cursor: { strokeDasharray: "4 4" },
3268
+ content: /* @__PURE__ */ jsx(ProductBarTooltip, {})
3269
+ }
3270
+ ),
3271
+ /* @__PURE__ */ jsx(
3272
+ Scatter,
3273
+ {
3274
+ name: "Products",
3275
+ data: viewsVsUnitsScatterData,
3276
+ fill: VIEWS_COLOR
3277
+ }
3278
+ )
3279
+ ] }) }) }) })
3280
+ }
3281
+ )
2157
3282
  ] });
2158
3283
  }
2159
3284
  const ANALYTICS_MODULES = [
@@ -2170,16 +3295,29 @@ const AnalyticsPage = () => {
2170
3295
  /* @__PURE__ */ jsx(Heading, { level: "h1", className: "tracking-tight", children: "Analytics" }),
2171
3296
  /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "Review orders, customers, and products in one organized workspace." })
2172
3297
  ] }),
2173
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 rounded-2xl border border-ui-border-base bg-ui-bg-subtle p-1.5", children: ANALYTICS_MODULES.map((m) => /* @__PURE__ */ jsx(
2174
- Button,
3298
+ /* @__PURE__ */ jsx(
3299
+ "div",
2175
3300
  {
2176
- variant: activeModule === m.id ? "secondary" : "transparent",
2177
- size: "small",
2178
- onClick: () => setActiveModule(m.id),
2179
- children: m.label
2180
- },
2181
- m.id
2182
- )) })
3301
+ className: "flex flex-wrap items-center gap-1 rounded-2xl border border-ui-border-base bg-ui-bg-subtle p-1",
3302
+ role: "tablist",
3303
+ "aria-label": "Analytics modules",
3304
+ children: ANALYTICS_MODULES.map((m) => {
3305
+ const active = activeModule === m.id;
3306
+ return /* @__PURE__ */ jsx(
3307
+ "button",
3308
+ {
3309
+ type: "button",
3310
+ role: "tab",
3311
+ "aria-selected": active,
3312
+ onClick: () => setActiveModule(m.id),
3313
+ className: `rounded-xl px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-fg-interactive focus-visible:ring-offset-2 focus-visible:ring-offset-ui-bg-base ${active ? "bg-ui-bg-base text-ui-fg-base shadow-sm" : "text-ui-fg-muted hover:bg-ui-bg-base/60 hover:text-ui-fg-base"}`.trim(),
3314
+ children: m.label
3315
+ },
3316
+ m.id
3317
+ );
3318
+ })
3319
+ }
3320
+ )
2183
3321
  ] }),
2184
3322
  /* @__PURE__ */ jsx("div", { className: "h-1 bg-ui-bg-subtle" })
2185
3323
  ] }),