medusa-analytics 0.0.19 → 0.0.21

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.
@@ -296,37 +296,72 @@ function formatChartLabel$2(value) {
296
296
  function formatPercent(value) {
297
297
  return `${value.toFixed(1)}%`;
298
298
  }
299
- function ordersCountFromPiePayload(payload) {
300
- if (typeof payload !== "object" || payload === null) return 0;
301
- if (!("orders_count" in payload)) return 0;
302
- const c = payload.orders_count;
303
- return Math.floor(Number(c) || 0);
304
- }
305
299
  function formatShortNumber$1(value) {
306
300
  return new Intl.NumberFormat("en-IN", {
307
301
  notation: "compact",
308
302
  maximumFractionDigits: value < 10 ? 1 : 0
309
303
  }).format(value);
310
304
  }
311
- function OrdersTrendTooltip({
305
+ const SALES_GRANULARITY_TABS = [
306
+ { value: "day", label: "Day" },
307
+ { value: "hour", label: "Hour" },
308
+ { value: "week", label: "Week" },
309
+ { value: "month", label: "Month" }
310
+ ];
311
+ function monthKeyFromDateStr(dateStr) {
312
+ if (dateStr.length >= 7) return dateStr.slice(0, 7);
313
+ return dateStr;
314
+ }
315
+ function formatMonthBucketLabel(ymKey) {
316
+ const [ys, ms] = ymKey.split("-");
317
+ const y = Number(ys);
318
+ const m = Number(ms);
319
+ if (!Number.isFinite(y) || !Number.isFinite(m)) return ymKey;
320
+ return new Intl.DateTimeFormat("en-IN", {
321
+ month: "short",
322
+ year: "numeric",
323
+ timeZone: "UTC"
324
+ }).format(new Date(Date.UTC(y, m - 1, 1)));
325
+ }
326
+ function aggregateDailyOrdersForBreakdown(rows, keyFn, labelFn) {
327
+ const map = /* @__PURE__ */ new Map();
328
+ for (const d of rows) {
329
+ const key = keyFn(d);
330
+ const cur = map.get(key) ?? { orders: 0, revenue: 0, bucketRows: [] };
331
+ cur.orders += d.orders_count;
332
+ cur.revenue += d.total_revenue;
333
+ cur.bucketRows.push(d);
334
+ map.set(key, cur);
335
+ }
336
+ return Array.from(map.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([key, v]) => ({
337
+ key,
338
+ label: labelFn(key, v.bucketRows),
339
+ orders_count: v.orders,
340
+ revenue: v.revenue
341
+ }));
342
+ }
343
+ function isSalesBreakdownBarRow(value) {
344
+ if (typeof value !== "object" || value === null) return false;
345
+ const v = value;
346
+ return typeof v.key === "string" && typeof v.label === "string" && typeof v.orders_count === "number" && typeof v.revenue === "number";
347
+ }
348
+ function SalesBreakdownTooltip({
312
349
  active,
313
- payload,
314
- label
350
+ payload
315
351
  }) {
316
- var _a, _b, _c, _d;
352
+ var _a, _b;
317
353
  if (!active || !(payload == null ? void 0 : payload.length)) return null;
318
- const row = isDailyOrderRow((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
319
- const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : "");
320
- const orders = ((_c = payload.find((entry) => entry.name === "Orders")) == null ? void 0 : _c.value) ?? 0;
321
- const revenue = ((_d = payload.find((entry) => entry.name === "Revenue")) == null ? void 0 : _d.value) ?? 0;
322
- return /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { title: displayLabel, children: [
354
+ const row = isSalesBreakdownBarRow((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
355
+ if (!row) return null;
356
+ return /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title: row.label, children: [
323
357
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
324
- "Orders: ",
325
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(orders).toLocaleString() })
358
+ "Revenue: ",
359
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(row.revenue) })
326
360
  ] }),
327
361
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
328
- "Revenue: ",
329
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(Number(revenue)) })
362
+ "Orders:",
363
+ " ",
364
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(row.orders_count).toLocaleString() })
330
365
  ] })
331
366
  ] });
332
367
  }
@@ -348,21 +383,6 @@ function OrdersTodayTooltip({
348
383
  (row == null ? void 0 : row.isToday) ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#6B7280" }, children: "Current day" }) : null
349
384
  ] });
350
385
  }
351
- function OrdersSparklineTooltip({
352
- active,
353
- payload,
354
- label
355
- }) {
356
- var _a, _b, _c;
357
- if (!active || !(payload == null ? void 0 : payload.length)) return null;
358
- const row = isDailyOrderRow((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
359
- const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : "");
360
- const orders = Number((_c = payload[0]) == null ? void 0 : _c.value) || 0;
361
- return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsTooltipCard, { variant: "compact", title: displayLabel, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
362
- "Orders: ",
363
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(orders).toLocaleString() })
364
- ] }) });
365
- }
366
386
  function OutcomesTrendTooltip({
367
387
  active,
368
388
  payload,
@@ -379,6 +399,53 @@ function OutcomesTrendTooltip({
379
399
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(Number(entry.value) || 0).toLocaleString() })
380
400
  ] }, String(entry.name))) });
381
401
  }
402
+ function isTrendRowDetailed(value) {
403
+ if (!isDailyOrderRow(value)) return false;
404
+ const v = value;
405
+ return typeof v.aov === "number" && typeof v.prev_revenue === "number" && typeof v.prev_orders === "number" && typeof v.prev_aov === "number";
406
+ }
407
+ function CombinedMetricsTooltip({
408
+ active,
409
+ payload
410
+ }) {
411
+ var _a, _b;
412
+ if (!active || !(payload == null ? void 0 : payload.length)) return null;
413
+ const row = isTrendRowDetailed((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
414
+ if (!row) return null;
415
+ const title = row.label ?? formatChartLabel$2(row.date);
416
+ return /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title, children: [
417
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
418
+ "Revenue:",
419
+ " ",
420
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCompactCurrency$1(row.total_revenue) }),
421
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
422
+ " ",
423
+ "· prev ",
424
+ formatCompactCurrency$1(row.prev_revenue)
425
+ ] })
426
+ ] }),
427
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
428
+ "Orders:",
429
+ " ",
430
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(row.orders_count).toLocaleString() }),
431
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
432
+ " ",
433
+ "· prev ",
434
+ Math.floor(row.prev_orders).toLocaleString()
435
+ ] })
436
+ ] }),
437
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
438
+ "AOV (non-canc.):",
439
+ " ",
440
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(row.aov) }),
441
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
442
+ " ",
443
+ "· prev ",
444
+ formatCurrency$1(row.prev_aov)
445
+ ] })
446
+ ] })
447
+ ] });
448
+ }
382
449
  const KPI_ICON_BG$2 = {
383
450
  green: "bg-emerald-500/20",
384
451
  blue: "bg-sky-500/20",
@@ -392,53 +459,6 @@ const KPI_ICONS$2 = {
392
459
  amber: icons.Cash
393
460
  };
394
461
  const PIE_PALETTE = ["#6366F1", "#94A3B8", "#10B981", "#F59E0B"];
395
- function TrafficRevenueDonut({ traffic }) {
396
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[152px] w-full shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { margin: { top: 2, right: 2, left: 2, bottom: 2 }, children: [
397
- /* @__PURE__ */ jsxRuntime.jsx(
398
- recharts.Pie,
399
- {
400
- data: traffic,
401
- dataKey: "revenue",
402
- nameKey: "label",
403
- cx: "50%",
404
- cy: "48%",
405
- innerRadius: 34,
406
- outerRadius: 54,
407
- paddingAngle: 2,
408
- children: traffic.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Cell, { fill: PIE_PALETTE[i % PIE_PALETTE.length] }, `traffic-slice-${i}`))
409
- }
410
- ),
411
- /* @__PURE__ */ jsxRuntime.jsx(
412
- recharts.Tooltip,
413
- {
414
- content: ({ active, payload }) => {
415
- var _a, _b, _c;
416
- return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title: String(((_a = payload[0]) == null ? void 0 : _a.name) ?? ""), children: [
417
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
418
- "Revenue:",
419
- " ",
420
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(Number((_b = payload[0]) == null ? void 0 : _b.value) || 0) })
421
- ] }),
422
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
423
- "Orders:",
424
- " ",
425
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: ordersCountFromPiePayload((_c = payload[0]) == null ? void 0 : _c.payload).toLocaleString() })
426
- ] })
427
- ] }) : null;
428
- }
429
- }
430
- ),
431
- /* @__PURE__ */ jsxRuntime.jsx(
432
- recharts.Legend,
433
- {
434
- wrapperStyle: { fontSize: 9, paddingTop: 0 },
435
- verticalAlign: "bottom",
436
- height: 22,
437
- iconType: "circle"
438
- }
439
- )
440
- ] }) }) });
441
- }
442
462
  function AtlasKpiCard$2({
443
463
  label,
444
464
  value,
@@ -498,7 +518,7 @@ function EmptyAnalyticsPanel$1({
498
518
  ] });
499
519
  }
500
520
  function OrdersDashboard() {
501
- var _a, _b, _c;
521
+ var _a, _b;
502
522
  const [data, setData] = react.useState(null);
503
523
  const [loading, setLoading] = react.useState(true);
504
524
  const [error, setError] = react.useState(null);
@@ -514,6 +534,7 @@ function OrdersDashboard() {
514
534
  const [todayContext, setTodayContext] = react.useState([]);
515
535
  const [todayContextLoading, setTodayContextLoading] = react.useState(true);
516
536
  const [todayContextError, setTodayContextError] = react.useState(null);
537
+ const [salesGranularity, setSalesGranularity] = react.useState("day");
517
538
  react.useEffect(() => {
518
539
  let cancelled = false;
519
540
  setLoading(true);
@@ -709,14 +730,61 @@ function OrdersDashboard() {
709
730
  revenue: h.revenue
710
731
  }));
711
732
  }, [ordersInsights]);
712
- const weekdayChartRows = react.useMemo(() => {
713
- if (!ordersInsights) return [];
714
- return ordersInsights.byWeekday.map((w) => ({
715
- label: w.label,
716
- orders_count: w.orders_count,
717
- revenue: w.revenue
733
+ const salesBreakdownChartRows = react.useMemo(() => {
734
+ if (salesGranularity === "hour") {
735
+ return hourlyChartRows.map((h) => ({
736
+ key: `hour-${h.hour}`,
737
+ label: h.label,
738
+ orders_count: h.orders_count,
739
+ revenue: h.revenue
740
+ }));
741
+ }
742
+ if (salesGranularity === "week") {
743
+ if (!ordersInsights) return [];
744
+ return ordersInsights.byWeekday.map((w) => ({
745
+ key: `weekday-${w.weekday}`,
746
+ label: w.label,
747
+ orders_count: w.orders_count,
748
+ revenue: w.revenue
749
+ }));
750
+ }
751
+ if (salesGranularity === "month") {
752
+ return aggregateDailyOrdersForBreakdown(
753
+ dailyOrders,
754
+ (d) => monthKeyFromDateStr(d.date),
755
+ (ymKey) => formatMonthBucketLabel(ymKey)
756
+ );
757
+ }
758
+ return dailyOrders.map((d) => ({
759
+ key: d.date,
760
+ label: d.label ?? formatChartLabel$2(d.date),
761
+ orders_count: d.orders_count,
762
+ revenue: d.total_revenue
718
763
  }));
719
- }, [ordersInsights]);
764
+ }, [salesGranularity, dailyOrders, hourlyChartRows, ordersInsights]);
765
+ const salesBreakdownDescription = react.useMemo(() => {
766
+ var _a2;
767
+ const rangeLabel = ((_a2 = OVER_TIME_PERIODS.find((p) => p.value === overTimePeriod)) == null ? void 0 : _a2.label) ?? "selected range";
768
+ const insightsHint = `Order-time breakdown uses last ${insightsWindowDays} days (UTC).`;
769
+ switch (salesGranularity) {
770
+ case "day":
771
+ return `Revenue by calendar day for ${rangeLabel} (aligned with Revenue & orders).`;
772
+ case "hour":
773
+ return `${insightsHint} Bars show revenue by hour of day.`;
774
+ case "week":
775
+ return `Revenue by UTC weekday — last ${insightsWindowDays} days.`;
776
+ case "month":
777
+ return `Revenue summed by calendar month (UTC) across ${rangeLabel}.`;
778
+ default:
779
+ return "";
780
+ }
781
+ }, [salesGranularity, overTimePeriod, insightsWindowDays]);
782
+ const salesBreakdownXAxisInterval = react.useMemo(() => {
783
+ const n = salesBreakdownChartRows.length;
784
+ if (salesGranularity === "hour") return 3;
785
+ if (salesGranularity === "day" && n > 24) return Math.max(0, Math.ceil(n / 10) - 1);
786
+ return 0;
787
+ }, [salesGranularity, salesBreakdownChartRows.length]);
720
788
  const ordersVsDraftsPie = react.useMemo(() => {
721
789
  var _a2;
722
790
  if (!ordersInsights) return [];
@@ -753,10 +821,6 @@ function OrdersDashboard() {
753
821
  };
754
822
  });
755
823
  }, [dailyOrders]);
756
- const trafficTotalRevenue = react.useMemo(
757
- () => (ordersInsights == null ? void 0 : ordersInsights.traffic.reduce((sum, t) => sum + (t.revenue || 0), 0)) ?? 0,
758
- [ordersInsights]
759
- );
760
824
  const quickPulseMetrics = [
761
825
  {
762
826
  label: "Range revenue",
@@ -797,6 +861,84 @@ function OrdersDashboard() {
797
861
  if (error || !data) {
798
862
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger", children: error ?? "Failed to load analytics" }) });
799
863
  }
864
+ const needsSalesOverTime = salesGranularity === "day" || salesGranularity === "month";
865
+ const needsSalesInsights = salesGranularity === "hour" || salesGranularity === "week";
866
+ const salesBreakdownBody = (() => {
867
+ if (needsSalesOverTime && overTimeLoading) {
868
+ return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[min(176px,28vh)] items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading chart…" }) }) });
869
+ }
870
+ if (needsSalesOverTime && overTimeError) {
871
+ return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[min(176px,28vh)] items-center justify-center px-2 py-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: overTimeError }) }) });
872
+ }
873
+ if (needsSalesInsights && insightsLoading) {
874
+ return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[min(176px,28vh)] items-center justify-center py-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading chart…" }) }) });
875
+ }
876
+ if (needsSalesInsights && insightsError) {
877
+ return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[min(176px,28vh)] items-center justify-center px-2 py-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) });
878
+ }
879
+ if (salesBreakdownChartRows.length === 0) {
880
+ return /* @__PURE__ */ jsxRuntime.jsx(
881
+ EmptyAnalyticsPanel$1,
882
+ {
883
+ title: "No sales data",
884
+ description: "Nothing to show for this view and range."
885
+ }
886
+ );
887
+ }
888
+ return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(200px,30vh)] min-h-[160px] w-full sm:h-[min(220px,32vh)]", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
889
+ recharts.BarChart,
890
+ {
891
+ data: salesBreakdownChartRows,
892
+ margin: { top: 4, right: 8, left: 4, bottom: 4 },
893
+ children: [
894
+ /* @__PURE__ */ jsxRuntime.jsx(
895
+ recharts.CartesianGrid,
896
+ {
897
+ strokeDasharray: "3 3",
898
+ vertical: false,
899
+ stroke: "rgba(148,163,184,0.12)"
900
+ }
901
+ ),
902
+ /* @__PURE__ */ jsxRuntime.jsx(
903
+ recharts.XAxis,
904
+ {
905
+ dataKey: "label",
906
+ tick: CHART_AXIS_TICK_SM$1,
907
+ tickLine: false,
908
+ axisLine: false,
909
+ interval: salesBreakdownXAxisInterval
910
+ }
911
+ ),
912
+ /* @__PURE__ */ jsxRuntime.jsx(
913
+ recharts.YAxis,
914
+ {
915
+ width: 44,
916
+ tick: CHART_AXIS_TICK_SM$1,
917
+ tickLine: false,
918
+ axisLine: false,
919
+ tickFormatter: (v) => formatCompactCurrency$1(Number(v))
920
+ }
921
+ ),
922
+ /* @__PURE__ */ jsxRuntime.jsx(
923
+ recharts.Tooltip,
924
+ {
925
+ content: /* @__PURE__ */ jsxRuntime.jsx(SalesBreakdownTooltip, {}),
926
+ cursor: { fill: "rgba(148,163,184,0.08)" }
927
+ }
928
+ ),
929
+ /* @__PURE__ */ jsxRuntime.jsx(
930
+ recharts.Bar,
931
+ {
932
+ dataKey: "revenue",
933
+ name: "Revenue",
934
+ fill: "#D946EF",
935
+ radius: [6, 6, 0, 0]
936
+ }
937
+ )
938
+ ]
939
+ }
940
+ ) }) }) });
941
+ })();
800
942
  return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsDashboardShell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-2xl border border-ui-border-base/80 bg-ui-bg-base shadow-sm", children: [
801
943
  /* @__PURE__ */ jsxRuntime.jsx(
802
944
  AnalyticsDashboardHeader,
@@ -911,397 +1053,197 @@ function OrdersDashboard() {
911
1053
  ] }) })
912
1054
  ] }),
913
1055
  !overTimeLoading && !overTimeError && dailyOrders.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
914
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-1.5 lg:grid-cols-3", children: [
915
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
916
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Revenue over time" }),
917
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[118px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
918
- recharts.LineChart,
919
- {
920
- data: trendRowsDetailed,
921
- margin: { top: 4, right: 4, left: 0, bottom: 0 },
922
- children: [
923
- /* @__PURE__ */ jsxRuntime.jsx(
924
- recharts.CartesianGrid,
925
- {
926
- strokeDasharray: "3 3",
927
- vertical: false,
928
- stroke: "rgba(148,163,184,0.12)"
929
- }
930
- ),
931
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
932
- /* @__PURE__ */ jsxRuntime.jsx(
933
- recharts.YAxis,
934
- {
935
- width: 36,
936
- tick: CHART_AXIS_TICK_SM$1,
937
- tickFormatter: (v) => formatCompactCurrency$1(Number(v))
938
- }
939
- ),
940
- /* @__PURE__ */ jsxRuntime.jsx(
941
- recharts.Tooltip,
942
- {
943
- content: ({ active, payload, label }) => {
944
- var _a2, _b2, _c2, _d;
945
- return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsxs(
946
- AnalyticsTooltipCard,
947
- {
948
- variant: "compact",
949
- title: String(
950
- isDailyOrderRow((_a2 = payload[0]) == null ? void 0 : _a2.payload) ? ((_b2 = payload[0]) == null ? void 0 : _b2.payload.label) ?? formatChartLabel$2(String(label)) : label
951
- ),
952
- children: [
953
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
954
- "This:",
955
- " ",
956
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCompactCurrency$1(
957
- Number(
958
- (_c2 = payload.find((p) => p.dataKey === "total_revenue")) == null ? void 0 : _c2.value
959
- ) || 0
960
- ) })
961
- ] }),
962
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
963
- "Previous:",
964
- " ",
965
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCompactCurrency$1(
966
- Number(
967
- (_d = payload.find((p) => p.dataKey === "prev_revenue")) == null ? void 0 : _d.value
968
- ) || 0
969
- ) })
970
- ] })
971
- ]
972
- }
973
- ) : null;
974
- }
975
- }
976
- ),
977
- /* @__PURE__ */ jsxRuntime.jsx(
978
- recharts.Line,
979
- {
980
- type: "natural",
981
- dataKey: "total_revenue",
982
- name: "This period",
983
- stroke: "#D946EF",
984
- strokeWidth: 2,
985
- dot: false
986
- }
987
- ),
988
- /* @__PURE__ */ jsxRuntime.jsx(
989
- recharts.Line,
990
- {
991
- type: "natural",
992
- dataKey: "prev_revenue",
993
- name: "Previous",
994
- stroke: "#94a3b8",
995
- strokeWidth: 1.5,
996
- strokeDasharray: "5 4",
997
- dot: false
998
- }
999
- )
1000
- ]
1001
- }
1002
- ) }) })
1003
- ] }),
1004
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1005
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Orders count" }),
1006
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[118px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1007
- recharts.LineChart,
1008
- {
1009
- data: trendRowsDetailed,
1010
- margin: { top: 4, right: 4, left: 0, bottom: 0 },
1011
- children: [
1012
- /* @__PURE__ */ jsxRuntime.jsx(
1013
- recharts.CartesianGrid,
1014
- {
1015
- strokeDasharray: "3 3",
1016
- vertical: false,
1017
- stroke: "rgba(148,163,184,0.12)"
1018
- }
1019
- ),
1020
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
1021
- /* @__PURE__ */ jsxRuntime.jsx(
1022
- recharts.YAxis,
1023
- {
1024
- width: 28,
1025
- tick: CHART_AXIS_TICK_SM$1,
1026
- allowDecimals: false
1027
- }
1028
- ),
1029
- /* @__PURE__ */ jsxRuntime.jsx(
1030
- recharts.Tooltip,
1031
- {
1032
- content: ({ active, payload, label }) => {
1033
- var _a2, _b2;
1034
- return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title: String(label), children: [
1035
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1036
- "This:",
1037
- " ",
1038
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(
1039
- Number(
1040
- (_a2 = payload.find((p) => p.dataKey === "orders_count")) == null ? void 0 : _a2.value
1041
- ) || 0
1042
- ).toLocaleString() })
1043
- ] }),
1044
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1045
- "Previous:",
1046
- " ",
1047
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(
1048
- Number(
1049
- (_b2 = payload.find((p) => p.dataKey === "prev_orders")) == null ? void 0 : _b2.value
1050
- ) || 0
1051
- ).toLocaleString() })
1052
- ] })
1053
- ] }) : null;
1054
- }
1055
- }
1056
- ),
1057
- /* @__PURE__ */ jsxRuntime.jsx(
1058
- recharts.Line,
1059
- {
1060
- type: "natural",
1061
- dataKey: "orders_count",
1062
- name: "This period",
1063
- stroke: "#38BDF8",
1064
- strokeWidth: 2,
1065
- dot: false
1066
- }
1067
- ),
1068
- /* @__PURE__ */ jsxRuntime.jsx(
1069
- recharts.Line,
1070
- {
1071
- type: "natural",
1072
- dataKey: "prev_orders",
1073
- name: "Previous",
1074
- stroke: "#94a3b8",
1075
- strokeWidth: 1.5,
1076
- strokeDasharray: "5 4",
1077
- dot: false
1078
- }
1079
- )
1080
- ]
1081
- }
1082
- ) }) })
1056
+ /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1057
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex flex-col gap-0.5 sm:flex-row sm:items-start sm:justify-between", children: [
1058
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1059
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Revenue, orders & AOV" }),
1060
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[9px] leading-snug", children: "One timeline · solid = this range, dashed = previous period (same length)" })
1061
+ ] }),
1062
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-3 gap-y-0.5 text-[9px] text-ui-fg-muted sm:justify-end", children: [
1063
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1064
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2 w-2 shrink-0 rounded-full bg-fuchsia-500" }),
1065
+ "Revenue"
1066
+ ] }),
1067
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1068
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2 w-2 shrink-0 rounded-full bg-sky-400" }),
1069
+ "Orders"
1070
+ ] }),
1071
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1072
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2 w-2 shrink-0 rounded-full bg-amber-500" }),
1073
+ "AOV"
1074
+ ] }),
1075
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1076
+ /* @__PURE__ */ jsxRuntime.jsx(
1077
+ "span",
1078
+ {
1079
+ className: "h-0 w-4 shrink-0 border-t border-dashed border-slate-400",
1080
+ "aria-hidden": true
1081
+ }
1082
+ ),
1083
+ "Previous"
1084
+ ] })
1085
+ ] })
1083
1086
  ] }),
1084
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1085
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "AOV (non-cancelled)" }),
1086
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[118px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1087
- recharts.LineChart,
1088
- {
1089
- data: trendRowsDetailed,
1090
- margin: { top: 4, right: 4, left: 0, bottom: 0 },
1091
- children: [
1092
- /* @__PURE__ */ jsxRuntime.jsx(
1093
- recharts.CartesianGrid,
1094
- {
1095
- strokeDasharray: "3 3",
1096
- vertical: false,
1097
- stroke: "rgba(148,163,184,0.12)"
1098
- }
1099
- ),
1100
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
1101
- /* @__PURE__ */ jsxRuntime.jsx(
1102
- recharts.YAxis,
1103
- {
1104
- width: 36,
1105
- tick: CHART_AXIS_TICK_SM$1,
1106
- tickFormatter: (v) => formatCompactCurrency$1(Number(v))
1107
- }
1108
- ),
1109
- /* @__PURE__ */ jsxRuntime.jsx(
1110
- recharts.Tooltip,
1111
- {
1112
- content: ({ active, payload, label }) => {
1113
- var _a2, _b2;
1114
- return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title: String(label), children: [
1115
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1116
- "This:",
1117
- " ",
1118
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(
1119
- Number(
1120
- (_a2 = payload.find((p) => p.dataKey === "aov")) == null ? void 0 : _a2.value
1121
- ) || 0
1122
- ) })
1123
- ] }),
1124
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1125
- "Previous:",
1126
- " ",
1127
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(
1128
- Number(
1129
- (_b2 = payload.find((p) => p.dataKey === "prev_aov")) == null ? void 0 : _b2.value
1130
- ) || 0
1131
- ) })
1132
- ] })
1133
- ] }) : null;
1134
- }
1135
- }
1136
- ),
1137
- /* @__PURE__ */ jsxRuntime.jsx(
1138
- recharts.Line,
1139
- {
1140
- type: "natural",
1141
- dataKey: "aov",
1142
- name: "This period",
1143
- stroke: "#D97706",
1144
- strokeWidth: 2,
1145
- dot: false
1146
- }
1147
- ),
1148
- /* @__PURE__ */ jsxRuntime.jsx(
1149
- recharts.Line,
1150
- {
1151
- type: "natural",
1152
- dataKey: "prev_aov",
1153
- name: "Previous",
1154
- stroke: "#94a3b8",
1155
- strokeWidth: 1.5,
1156
- strokeDasharray: "5 4",
1157
- dot: false
1158
- }
1159
- )
1160
- ]
1161
- }
1162
- ) }) })
1163
- ] })
1164
- ] }),
1165
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", className: "mt-1.5", children: [
1166
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Revenue breakdown (stacked — by order status)" }),
1167
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(168px,26vh)] min-h-[140px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1087
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(220px,32vh)] min-h-[156px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1168
1088
  recharts.ComposedChart,
1169
1089
  {
1170
- data: dailyOrders,
1171
- margin: { top: 4, right: 8, left: -4, bottom: 0 },
1090
+ data: trendRowsDetailed,
1091
+ margin: { top: 6, right: 8, left: 2, bottom: 4 },
1172
1092
  children: [
1173
1093
  /* @__PURE__ */ jsxRuntime.jsx(
1174
1094
  recharts.CartesianGrid,
1175
1095
  {
1176
- stroke: "rgba(148,163,184,0.14)",
1177
1096
  strokeDasharray: "3 3",
1178
- vertical: false
1097
+ vertical: false,
1098
+ stroke: "rgba(148,163,184,0.12)"
1179
1099
  }
1180
1100
  ),
1181
1101
  /* @__PURE__ */ jsxRuntime.jsx(
1182
1102
  recharts.XAxis,
1183
1103
  {
1184
1104
  dataKey: "date",
1185
- tick: CHART_AXIS_TICK$2,
1105
+ tick: CHART_AXIS_TICK_SM$1,
1186
1106
  tickLine: false,
1187
1107
  axisLine: false,
1188
1108
  tickFormatter: (value, index) => {
1189
- const row = dailyOrders[index];
1190
- return (row == null ? void 0 : row.label) ?? formatChartLabel$2(value);
1109
+ const row = trendRowsDetailed[index];
1110
+ return (row == null ? void 0 : row.label) ?? formatChartLabel$2(String(value));
1191
1111
  }
1192
1112
  }
1193
1113
  ),
1194
1114
  /* @__PURE__ */ jsxRuntime.jsx(
1195
1115
  recharts.YAxis,
1196
1116
  {
1197
- tick: CHART_AXIS_TICK$2,
1117
+ yAxisId: "orders",
1118
+ width: 30,
1119
+ tick: CHART_AXIS_TICK_SM$1,
1120
+ tickLine: false,
1121
+ axisLine: false,
1122
+ allowDecimals: false,
1123
+ tickFormatter: (v) => Math.floor(Number(v) || 0).toLocaleString()
1124
+ }
1125
+ ),
1126
+ /* @__PURE__ */ jsxRuntime.jsx(
1127
+ recharts.YAxis,
1128
+ {
1129
+ yAxisId: "revenue",
1130
+ orientation: "right",
1131
+ width: 42,
1132
+ tick: CHART_AXIS_TICK_SM$1,
1133
+ tickLine: false,
1134
+ axisLine: false,
1135
+ tickFormatter: (v) => formatCompactCurrency$1(Number(v))
1136
+ }
1137
+ ),
1138
+ /* @__PURE__ */ jsxRuntime.jsx(
1139
+ recharts.YAxis,
1140
+ {
1141
+ yAxisId: "aov",
1142
+ orientation: "right",
1143
+ width: 40,
1144
+ tick: CHART_AXIS_TICK_SM$1,
1145
+ tickLine: false,
1146
+ axisLine: false,
1198
1147
  tickFormatter: (v) => formatCompactCurrency$1(Number(v))
1199
1148
  }
1200
1149
  ),
1201
1150
  /* @__PURE__ */ jsxRuntime.jsx(
1202
1151
  recharts.Tooltip,
1203
1152
  {
1204
- content: ({ active, payload, label }) => active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsTooltipCard, { variant: "compact", title: String(label), children: payload.map((p) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1205
- p.name,
1206
- ":",
1207
- " ",
1208
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(Number(p.value) || 0) })
1209
- ] }, String(p.name))) }) : null
1153
+ content: /* @__PURE__ */ jsxRuntime.jsx(CombinedMetricsTooltip, {}),
1154
+ cursor: {
1155
+ stroke: "rgba(248, 250, 252, 0.35)",
1156
+ strokeWidth: 1
1157
+ }
1210
1158
  }
1211
1159
  ),
1212
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, { wrapperStyle: { fontSize: 10 }, iconType: "circle" }),
1213
1160
  /* @__PURE__ */ jsxRuntime.jsx(
1214
- recharts.Area,
1161
+ recharts.Line,
1215
1162
  {
1163
+ yAxisId: "orders",
1216
1164
  type: "natural",
1217
- dataKey: "revenue_delivered",
1218
- name: "Delivered",
1219
- stackId: "r",
1220
- fill: "#10B981",
1221
- stroke: "#059669",
1222
- fillOpacity: 0.85
1165
+ dataKey: "orders_count",
1166
+ name: "Orders",
1167
+ stroke: "#38BDF8",
1168
+ strokeWidth: 2,
1169
+ dot: false
1223
1170
  }
1224
1171
  ),
1225
1172
  /* @__PURE__ */ jsxRuntime.jsx(
1226
- recharts.Area,
1173
+ recharts.Line,
1227
1174
  {
1175
+ yAxisId: "orders",
1228
1176
  type: "natural",
1229
- dataKey: "revenue_open",
1230
- name: "Open / pending",
1231
- stackId: "r",
1232
- fill: "#3B82F6",
1233
- stroke: "#2563eb",
1234
- fillOpacity: 0.85
1177
+ dataKey: "prev_orders",
1178
+ name: "Orders (prev)",
1179
+ stroke: "#64748b",
1180
+ strokeWidth: 1.5,
1181
+ strokeDasharray: "5 4",
1182
+ dot: false
1235
1183
  }
1236
1184
  ),
1237
1185
  /* @__PURE__ */ jsxRuntime.jsx(
1238
- recharts.Area,
1186
+ recharts.Line,
1239
1187
  {
1188
+ yAxisId: "revenue",
1240
1189
  type: "natural",
1241
- dataKey: "revenue_cancelled",
1242
- name: "Cancelled",
1243
- stackId: "r",
1244
- fill: "#F87171",
1245
- stroke: "#EF4444",
1246
- fillOpacity: 0.75
1190
+ dataKey: "total_revenue",
1191
+ name: "Revenue",
1192
+ stroke: "#D946EF",
1193
+ strokeWidth: 2,
1194
+ dot: false
1195
+ }
1196
+ ),
1197
+ /* @__PURE__ */ jsxRuntime.jsx(
1198
+ recharts.Line,
1199
+ {
1200
+ yAxisId: "revenue",
1201
+ type: "natural",
1202
+ dataKey: "prev_revenue",
1203
+ name: "Revenue (prev)",
1204
+ stroke: "#64748b",
1205
+ strokeWidth: 1.5,
1206
+ strokeDasharray: "5 4",
1207
+ dot: false
1208
+ }
1209
+ ),
1210
+ /* @__PURE__ */ jsxRuntime.jsx(
1211
+ recharts.Line,
1212
+ {
1213
+ yAxisId: "aov",
1214
+ type: "natural",
1215
+ dataKey: "aov",
1216
+ name: "AOV",
1217
+ stroke: "#D97706",
1218
+ strokeWidth: 2,
1219
+ dot: false
1220
+ }
1221
+ ),
1222
+ /* @__PURE__ */ jsxRuntime.jsx(
1223
+ recharts.Line,
1224
+ {
1225
+ yAxisId: "aov",
1226
+ type: "natural",
1227
+ dataKey: "prev_aov",
1228
+ name: "AOV (prev)",
1229
+ stroke: "#64748b",
1230
+ strokeWidth: 1.5,
1231
+ strokeDasharray: "5 4",
1232
+ dot: false
1247
1233
  }
1248
1234
  )
1249
1235
  ]
1250
1236
  }
1251
1237
  ) }) })
1252
- ] })
1253
- ] }) : null,
1254
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", className: "relative overflow-hidden", children: [
1255
- /* @__PURE__ */ jsxRuntime.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" }),
1256
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative space-y-1", children: [
1257
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-1.5", children: [
1258
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0", children: [
1259
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Trend overview" }),
1260
- /* @__PURE__ */ jsxRuntime.jsx(ui.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" })
1261
- ] }),
1262
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap justify-end gap-2 text-[10px] text-ui-fg-muted", children: [
1263
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1264
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-sky-400" }),
1265
- "Orders"
1266
- ] }),
1267
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1268
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-fuchsia-400" }),
1269
- "Revenue"
1270
- ] })
1271
- ] })
1272
- ] }),
1273
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(200px,30vh)] min-h-[160px] sm:h-[min(216px,32vh)]", children: overTimeLoading ? /* @__PURE__ */ jsxRuntime.jsx(
1274
- "div",
1275
- {
1276
- className: "flex h-full items-center justify-center",
1277
- role: "status",
1278
- "aria-label": "Loading orders over time",
1279
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading chart…" })
1280
- }
1281
- ) : overTimeError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-xs", children: overTimeError }) }) : /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1238
+ ] }),
1239
+ /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", className: "mt-1.5", children: [
1240
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Revenue breakdown (stacked — by order status)" }),
1241
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(168px,26vh)] min-h-[140px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1282
1242
  recharts.ComposedChart,
1283
1243
  {
1284
1244
  data: dailyOrders,
1285
- margin: { top: 4, right: 6, left: -6, bottom: 0 },
1245
+ margin: { top: 4, right: 8, left: -4, bottom: 0 },
1286
1246
  children: [
1287
- /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
1288
- /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "ordersGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
1289
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#67E8F9" }),
1290
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#3B82F6" })
1291
- ] }),
1292
- /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "revenueGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
1293
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#F472B6" }),
1294
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#C084FC" })
1295
- ] }),
1296
- /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "ordersAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1297
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#38BDF8", stopOpacity: 0.22 }),
1298
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#38BDF8", stopOpacity: 0 })
1299
- ] }),
1300
- /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "revenueAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1301
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#E879F9", stopOpacity: 0.2 }),
1302
- /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#E879F9", stopOpacity: 0 })
1303
- ] })
1304
- ] }),
1305
1247
  /* @__PURE__ */ jsxRuntime.jsx(
1306
1248
  recharts.CartesianGrid,
1307
1249
  {
@@ -1326,156 +1268,85 @@ function OrdersDashboard() {
1326
1268
  /* @__PURE__ */ jsxRuntime.jsx(
1327
1269
  recharts.YAxis,
1328
1270
  {
1329
- yAxisId: "orders",
1330
- width: 32,
1331
- tick: CHART_AXIS_TICK$2,
1332
- tickLine: false,
1333
- axisLine: false,
1334
- allowDecimals: false,
1335
- tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
1336
- }
1337
- ),
1338
- /* @__PURE__ */ jsxRuntime.jsx(
1339
- recharts.YAxis,
1340
- {
1341
- yAxisId: "revenue",
1342
- orientation: "right",
1343
- width: 40,
1344
1271
  tick: CHART_AXIS_TICK$2,
1345
- tickLine: false,
1346
- axisLine: false,
1347
- tickFormatter: (value) => formatCompactCurrency$1(Number(value) || 0)
1272
+ tickFormatter: (v) => formatCompactCurrency$1(Number(v))
1348
1273
  }
1349
1274
  ),
1350
1275
  /* @__PURE__ */ jsxRuntime.jsx(
1351
1276
  recharts.Tooltip,
1352
1277
  {
1353
- content: /* @__PURE__ */ jsxRuntime.jsx(OrdersTrendTooltip, {}),
1354
- cursor: {
1355
- stroke: "rgba(248, 250, 252, 0.35)",
1356
- strokeWidth: 1
1357
- }
1278
+ content: ({ active, payload, label }) => active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsTooltipCard, { variant: "compact", title: String(label), children: payload.map((p) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1279
+ p.name,
1280
+ ":",
1281
+ " ",
1282
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(Number(p.value) || 0) })
1283
+ ] }, String(p.name))) }) : null
1358
1284
  }
1359
1285
  ),
1286
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, { wrapperStyle: { fontSize: 10 }, iconType: "circle" }),
1360
1287
  /* @__PURE__ */ jsxRuntime.jsx(
1361
1288
  recharts.Area,
1362
1289
  {
1363
- yAxisId: "orders",
1364
1290
  type: "natural",
1365
- dataKey: "orders_count",
1366
- stroke: "none",
1367
- fill: "url(#ordersAreaFill)",
1368
- isAnimationActive: false,
1369
- legendType: "none"
1291
+ dataKey: "revenue_delivered",
1292
+ name: "Delivered",
1293
+ stackId: "r",
1294
+ fill: "#10B981",
1295
+ stroke: "#059669",
1296
+ fillOpacity: 0.85
1370
1297
  }
1371
1298
  ),
1372
1299
  /* @__PURE__ */ jsxRuntime.jsx(
1373
1300
  recharts.Area,
1374
1301
  {
1375
- yAxisId: "revenue",
1376
- type: "natural",
1377
- dataKey: "total_revenue",
1378
- stroke: "none",
1379
- fill: "url(#revenueAreaFill)",
1380
- isAnimationActive: false,
1381
- legendType: "none"
1382
- }
1383
- ),
1384
- /* @__PURE__ */ jsxRuntime.jsx(
1385
- recharts.Line,
1386
- {
1387
- yAxisId: "orders",
1388
1302
  type: "natural",
1389
- dataKey: "orders_count",
1390
- name: "Orders",
1391
- stroke: "url(#ordersGradient)",
1392
- strokeWidth: 2,
1393
- dot: false,
1394
- activeDot: { r: 4, fill: STATUS_BAR_COLORS.orders }
1303
+ dataKey: "revenue_open",
1304
+ name: "Open / pending",
1305
+ stackId: "r",
1306
+ fill: "#3B82F6",
1307
+ stroke: "#2563eb",
1308
+ fillOpacity: 0.85
1395
1309
  }
1396
1310
  ),
1397
1311
  /* @__PURE__ */ jsxRuntime.jsx(
1398
- recharts.Line,
1312
+ recharts.Area,
1399
1313
  {
1400
- yAxisId: "revenue",
1401
1314
  type: "natural",
1402
- dataKey: "total_revenue",
1403
- name: "Revenue",
1404
- stroke: "url(#revenueGradient)",
1405
- strokeWidth: 2,
1406
- dot: false,
1407
- activeDot: { r: 4, fill: STATUS_BAR_COLORS.revenue }
1315
+ dataKey: "revenue_cancelled",
1316
+ name: "Cancelled",
1317
+ stackId: "r",
1318
+ fill: "#F87171",
1319
+ stroke: "#EF4444",
1320
+ fillOpacity: 0.75
1408
1321
  }
1409
1322
  )
1410
1323
  ]
1411
1324
  }
1412
1325
  ) }) })
1413
1326
  ] })
1414
- ] })
1327
+ ] }) : null
1415
1328
  ] })
1416
1329
  }
1417
1330
  ) }),
1418
1331
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 flex flex-col gap-2 xl:col-span-6", children: [
1419
- /* @__PURE__ */ jsxRuntime.jsxs(
1332
+ /* @__PURE__ */ jsxRuntime.jsx(
1420
1333
  AnalyticsSection,
1421
1334
  {
1422
1335
  variant: "atlas",
1423
1336
  title: "Pulse & range",
1424
- description: "Window totals and an orders time series for the selected range.",
1425
- children: [
1426
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: quickPulseMetrics.map((metric) => /* @__PURE__ */ jsxRuntime.jsxs(
1427
- "div",
1428
- {
1429
- className: `rounded-lg border border-ui-border-base bg-ui-bg-base px-2 py-2 shadow-sm ${metric.accentClassName}`.trim(),
1430
- children: [
1431
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: metric.label }),
1432
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base mt-0.5 text-sm font-semibold tracking-tight", children: metric.value }),
1433
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted mt-0.5 text-[9px] leading-snug", children: metric.helper })
1434
- ]
1435
- },
1436
- metric.label
1437
- )) }),
1438
- !overTimeLoading && !overTimeError && dailyOrders.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", className: "mt-1.5", children: [
1439
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Orders (time series)" }),
1440
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[76px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1441
- recharts.LineChart,
1442
- {
1443
- data: dailyOrders,
1444
- margin: { top: 2, right: 4, left: -18, bottom: 2 },
1445
- children: [
1446
- /* @__PURE__ */ jsxRuntime.jsx(
1447
- recharts.CartesianGrid,
1448
- {
1449
- strokeDasharray: "3 3",
1450
- vertical: false,
1451
- stroke: "rgba(148,163,184,0.12)"
1452
- }
1453
- ),
1454
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
1455
- /* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { hide: true, domain: ["auto", "auto"] }),
1456
- /* @__PURE__ */ jsxRuntime.jsx(
1457
- recharts.Tooltip,
1458
- {
1459
- content: /* @__PURE__ */ jsxRuntime.jsx(OrdersSparklineTooltip, {}),
1460
- cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 }
1461
- }
1462
- ),
1463
- /* @__PURE__ */ jsxRuntime.jsx(
1464
- recharts.Line,
1465
- {
1466
- type: "natural",
1467
- dataKey: "orders_count",
1468
- stroke: "#3b82f6",
1469
- strokeWidth: 2,
1470
- dot: { r: 2, fill: "#3b82f6" },
1471
- activeDot: { r: 3 }
1472
- }
1473
- )
1474
- ]
1475
- }
1476
- ) }) })
1477
- ] }) : null
1478
- ]
1337
+ description: "Window totals for the selected range.",
1338
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: quickPulseMetrics.map((metric) => /* @__PURE__ */ jsxRuntime.jsxs(
1339
+ "div",
1340
+ {
1341
+ className: `rounded-lg border border-ui-border-base bg-ui-bg-base px-2 py-2 shadow-sm ${metric.accentClassName}`.trim(),
1342
+ children: [
1343
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: metric.label }),
1344
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base mt-0.5 text-sm font-semibold tracking-tight", children: metric.value }),
1345
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted mt-0.5 text-[9px] leading-snug", children: metric.helper })
1346
+ ]
1347
+ },
1348
+ metric.label
1349
+ )) })
1479
1350
  }
1480
1351
  ),
1481
1352
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1483,7 +1354,7 @@ function OrdersDashboard() {
1483
1354
  {
1484
1355
  variant: "atlas",
1485
1356
  title: "Order → fulfillment funnel",
1486
- description: `Stages by order created date (UTC), same range as Revenue & orders (${((_c = OVER_TIME_PERIODS.find((p) => p.value === overTimePeriod)) == null ? void 0 : _c.label) ?? "period"}). Not storefront visitors.`,
1357
+ description: `Stages by order created date (UTC), same range as Revenue & orders (${((_b = OVER_TIME_PERIODS.find((p) => p.value === overTimePeriod)) == null ? void 0 : _b.label) ?? "period"}). Not storefront visitors.`,
1487
1358
  children: overTimeLoading ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[120px] items-center justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : overTimeError ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[120px] items-center justify-center px-2 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: overTimeError }) }) }) : funnelTimeSeriesRows.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1488
1359
  /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
1489
1360
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Stage counts (time series)" }),
@@ -1714,21 +1585,6 @@ function OrdersDashboard() {
1714
1585
  }
1715
1586
  )
1716
1587
  }
1717
- ),
1718
- /* @__PURE__ */ jsxRuntime.jsx(
1719
- AnalyticsSection,
1720
- {
1721
- variant: "atlas",
1722
- title: "Order revenue (attribution)",
1723
- description: "All revenue is from captured Medusa orders until storefront channel data exists.",
1724
- children: insightsLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : insightsError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) : ordersInsights && ordersInsights.traffic.length > 0 ? trafficTotalRevenue <= 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.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__ */ jsxRuntime.jsx(TrafficRevenueDonut, { traffic: ordersInsights.traffic }) : /* @__PURE__ */ jsxRuntime.jsx(
1725
- EmptyAnalyticsPanel$1,
1726
- {
1727
- title: "No order revenue",
1728
- description: "No orders in this window."
1729
- }
1730
- )
1731
- }
1732
1588
  )
1733
1589
  ] })
1734
1590
  ] }),
@@ -1970,86 +1826,46 @@ function OrdersDashboard() {
1970
1826
  }
1971
1827
  )
1972
1828
  ] }),
1973
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-2 md:grid-cols-3", children: [
1829
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-3 xl:grid-cols-12", children: [
1974
1830
  /* @__PURE__ */ jsxRuntime.jsx(
1975
1831
  AnalyticsSection,
1976
1832
  {
1977
1833
  variant: "atlas",
1978
- title: "Sales by weekday",
1979
- description: `Order revenue by UTC weekday — last ${insightsWindowDays} days.`,
1980
- children: insightsLoading ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : insightsError ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) }) : weekdayChartRows.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(176px,28vh)] min-h-[148px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1981
- recharts.BarChart,
1834
+ className: "xl:col-span-8",
1835
+ title: "Sales breakdown",
1836
+ description: salesBreakdownDescription,
1837
+ actionsBare: true,
1838
+ actions: /* @__PURE__ */ jsxRuntime.jsx(
1839
+ "div",
1982
1840
  {
1983
- data: weekdayChartRows,
1984
- margin: { top: 2, right: 4, left: -8, bottom: 2 },
1985
- children: [
1986
- /* @__PURE__ */ jsxRuntime.jsx(
1987
- recharts.CartesianGrid,
1988
- {
1989
- strokeDasharray: "3 3",
1990
- vertical: false,
1991
- stroke: "rgba(148,163,184,0.12)"
1992
- }
1993
- ),
1994
- /* @__PURE__ */ jsxRuntime.jsx(
1995
- recharts.XAxis,
1996
- {
1997
- dataKey: "label",
1998
- tick: CHART_AXIS_TICK$2
1999
- }
2000
- ),
2001
- /* @__PURE__ */ jsxRuntime.jsx(
2002
- recharts.YAxis,
2003
- {
2004
- width: 40,
2005
- tick: CHART_AXIS_TICK_SM$1,
2006
- tickFormatter: (v) => formatCompactCurrency$1(Number(v))
2007
- }
2008
- ),
2009
- /* @__PURE__ */ jsxRuntime.jsx(
2010
- recharts.Tooltip,
1841
+ className: "flex flex-wrap items-center gap-1 rounded-lg border border-ui-border-base bg-ui-bg-subtle/40 p-0.5",
1842
+ role: "tablist",
1843
+ "aria-label": "Sales breakdown granularity",
1844
+ children: SALES_GRANULARITY_TABS.map((tab) => {
1845
+ const selected = salesGranularity === tab.value;
1846
+ return /* @__PURE__ */ jsxRuntime.jsx(
1847
+ "button",
2011
1848
  {
2012
- content: ({ active, payload, label }) => {
2013
- var _a2, _b2;
2014
- return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title: String(label), children: [
2015
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2016
- "Revenue:",
2017
- " ",
2018
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(
2019
- Number(
2020
- (_a2 = payload.find((p) => p.dataKey === "revenue")) == null ? void 0 : _a2.value
2021
- ) || 0
2022
- ) })
2023
- ] }),
2024
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2025
- "Orders:",
2026
- " ",
2027
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(
2028
- Number(
2029
- (_b2 = payload.find((p) => p.dataKey === "orders_count")) == null ? void 0 : _b2.value
2030
- ) || 0
2031
- ).toLocaleString() })
2032
- ] })
2033
- ] }) : null;
2034
- }
2035
- }
2036
- ),
2037
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Bar, { dataKey: "revenue", name: "Revenue", fill: "#D946EF", radius: [4, 4, 0, 0] })
2038
- ]
2039
- }
2040
- ) }) }) }) : /* @__PURE__ */ jsxRuntime.jsx(
2041
- EmptyAnalyticsPanel$1,
2042
- {
2043
- title: "No weekday data",
2044
- description: "No orders in this window."
1849
+ type: "button",
1850
+ role: "tab",
1851
+ "aria-selected": selected,
1852
+ onClick: () => setSalesGranularity(tab.value),
1853
+ className: `rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-fg-interactive ${selected ? "bg-ui-bg-base text-ui-fg-base shadow-sm" : "text-ui-fg-muted hover:text-ui-fg-base"}`,
1854
+ children: tab.label
1855
+ },
1856
+ tab.value
1857
+ );
1858
+ })
2045
1859
  }
2046
- )
1860
+ ),
1861
+ children: salesBreakdownBody
2047
1862
  }
2048
1863
  ),
2049
1864
  /* @__PURE__ */ jsxRuntime.jsx(
2050
1865
  AnalyticsSection,
2051
1866
  {
2052
1867
  variant: "atlas",
1868
+ className: "xl:col-span-4",
2053
1869
  title: "Placed orders vs drafts",
2054
1870
  description: "Window order count vs current open draft orders (admin). Not storefront cart abandonment.",
2055
1871
  children: insightsLoading ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : insightsError ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) }) : ordersVsDraftsPie.some((s) => s.value > 0) ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
@@ -2108,82 +1924,6 @@ function OrdersDashboard() {
2108
1924
  }
2109
1925
  )
2110
1926
  }
2111
- ),
2112
- /* @__PURE__ */ jsxRuntime.jsx(
2113
- AnalyticsSection,
2114
- {
2115
- variant: "atlas",
2116
- title: "Sales by hour (UTC)",
2117
- description: `Orders created by hour — last ${insightsWindowDays} days.`,
2118
- children: insightsLoading ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : insightsError ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[100px] items-center justify-center px-2 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: insightsError }) }) }) : hourlyChartRows.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(176px,28vh)] min-h-[148px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
2119
- recharts.BarChart,
2120
- {
2121
- data: hourlyChartRows,
2122
- margin: { top: 2, right: 4, left: -8, bottom: 2 },
2123
- children: [
2124
- /* @__PURE__ */ jsxRuntime.jsx(
2125
- recharts.CartesianGrid,
2126
- {
2127
- strokeDasharray: "3 3",
2128
- vertical: false,
2129
- stroke: "rgba(148,163,184,0.12)"
2130
- }
2131
- ),
2132
- /* @__PURE__ */ jsxRuntime.jsx(
2133
- recharts.XAxis,
2134
- {
2135
- dataKey: "label",
2136
- interval: 3,
2137
- tick: CHART_AXIS_TICK_SM$1
2138
- }
2139
- ),
2140
- /* @__PURE__ */ jsxRuntime.jsx(
2141
- recharts.YAxis,
2142
- {
2143
- width: 28,
2144
- tick: CHART_AXIS_TICK$2,
2145
- allowDecimals: false
2146
- }
2147
- ),
2148
- /* @__PURE__ */ jsxRuntime.jsx(
2149
- recharts.Tooltip,
2150
- {
2151
- content: ({ active, payload, label }) => {
2152
- var _a2, _b2;
2153
- return active && (payload == null ? void 0 : payload.length) ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title: String(label), children: [
2154
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2155
- "Orders:",
2156
- " ",
2157
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(
2158
- Number(
2159
- (_a2 = payload.find((p) => p.dataKey === "orders_count")) == null ? void 0 : _a2.value
2160
- ) || 0
2161
- ).toLocaleString() })
2162
- ] }),
2163
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2164
- "Revenue:",
2165
- " ",
2166
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(
2167
- Number(
2168
- (_b2 = payload.find((p) => p.dataKey === "revenue")) == null ? void 0 : _b2.value
2169
- ) || 0
2170
- ) })
2171
- ] })
2172
- ] }) : null;
2173
- }
2174
- }
2175
- ),
2176
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Bar, { dataKey: "orders_count", name: "Orders", fill: "#38BDF8", radius: [4, 4, 0, 0] })
2177
- ]
2178
- }
2179
- ) }) }) }) : /* @__PURE__ */ jsxRuntime.jsx(
2180
- EmptyAnalyticsPanel$1,
2181
- {
2182
- title: "No hourly data",
2183
- description: "No orders in this window."
2184
- }
2185
- )
2186
- }
2187
1927
  )
2188
1928
  ] })
2189
1929
  ] })
@@ -2809,28 +2549,35 @@ function TrendTooltip({
2809
2549
  function MiniTrendTooltip({
2810
2550
  active,
2811
2551
  payload,
2812
- label
2552
+ label,
2553
+ productHeadline,
2554
+ hideViewsRow,
2555
+ hideUnitsRow,
2556
+ hideRevenueRow
2813
2557
  }) {
2814
2558
  var _a, _b, _c, _d, _e;
2815
2559
  if (!active || !(payload == null ? void 0 : payload.length)) return null;
2816
2560
  const row = isProductOverTimePoint((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
2817
- const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : "");
2561
+ const labelKey = label !== void 0 && label !== null ? String(label) : "";
2562
+ const displayLabel = (row == null ? void 0 : row.label) ?? (labelKey ? new Date(labelKey).toLocaleDateString() : "");
2818
2563
  const unitsSold = ((_c = payload.find((entry) => entry.name === "Units sold")) == null ? void 0 : _c.value) ?? 0;
2819
2564
  const views = ((_d = payload.find((entry) => entry.name === "Views")) == null ? void 0 : _d.value) ?? 0;
2820
2565
  const revenue = ((_e = payload.find((entry) => entry.name === "Revenue")) == null ? void 0 : _e.value) ?? 0;
2821
- return /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title: displayLabel, children: [
2822
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2566
+ const title = productHeadline ?? displayLabel;
2567
+ return /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsTooltipCard, { variant: "compact", title, children: [
2568
+ productHeadline ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 text-[10px] leading-tight opacity-80", children: displayLabel }) : null,
2569
+ !hideUnitsRow ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2823
2570
  "Units sold: ",
2824
2571
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(Number(unitsSold)).toLocaleString() })
2825
- ] }),
2826
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2572
+ ] }) : null,
2573
+ !hideViewsRow ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2827
2574
  "Views: ",
2828
2575
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(Number(views)).toLocaleString() })
2829
- ] }),
2830
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2576
+ ] }) : null,
2577
+ !hideRevenueRow ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2831
2578
  "Revenue: ",
2832
2579
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency(Number(revenue)) })
2833
- ] })
2580
+ ] }) : null
2834
2581
  ] });
2835
2582
  }
2836
2583
  function ProductBarTooltip({
@@ -2890,7 +2637,7 @@ function EmptyAnalyticsPanel({ title, description }) {
2890
2637
  ] });
2891
2638
  }
2892
2639
  function ProductsDashboard() {
2893
- var _a, _b, _c, _d, _e;
2640
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2894
2641
  const [summaryDays, setSummaryDays] = react.useState("all");
2895
2642
  const [graphPeriod, setGraphPeriod] = react.useState("one_week");
2896
2643
  const [topSellerPeriod, setTopSellerPeriod] = react.useState("week");
@@ -3017,14 +2764,43 @@ function ProductsDashboard() {
3017
2764
  };
3018
2765
  }, [salesChannelId, topSellerPeriod]);
3019
2766
  react.useEffect(() => {
2767
+ var _a2, _b2;
3020
2768
  let cancelled = false;
2769
+ if (topSellersLoading) {
2770
+ setBestSellersTrendLoading(true);
2771
+ return () => {
2772
+ cancelled = true;
2773
+ };
2774
+ }
2775
+ if (topSellersError) {
2776
+ setBestSellersTrendLoading(false);
2777
+ setBestSellersTrendError(topSellersError);
2778
+ setBestSellersTrend(null);
2779
+ return () => {
2780
+ cancelled = true;
2781
+ };
2782
+ }
2783
+ const topProductId = (_b2 = (_a2 = topSellers == null ? void 0 : topSellers.products) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.product_id;
2784
+ if (!topProductId) {
2785
+ setBestSellersTrendLoading(false);
2786
+ setBestSellersTrendError(null);
2787
+ setBestSellersTrend({
2788
+ series: [],
2789
+ productViewsConnected: (topSellers == null ? void 0 : topSellers.productViewsConnected) ?? false,
2790
+ product: null
2791
+ });
2792
+ return () => {
2793
+ cancelled = true;
2794
+ };
2795
+ }
3021
2796
  setBestSellersTrendLoading(true);
3022
2797
  setBestSellersTrendError(null);
3023
2798
  const period = topSellerPeriodToGraphPeriod(topSellerPeriod);
3024
2799
  fetch(
3025
2800
  buildAnalyticsUrl("/admin/analytics/products-over-time", {
3026
2801
  period,
3027
- sales_channel_id: salesChannelId !== "all" ? salesChannelId : null
2802
+ sales_channel_id: salesChannelId !== "all" ? salesChannelId : null,
2803
+ product_id: topProductId
3028
2804
  }),
3029
2805
  { credentials: "include" }
3030
2806
  ).then((res) => {
@@ -3042,16 +2818,53 @@ function ProductsDashboard() {
3042
2818
  return () => {
3043
2819
  cancelled = true;
3044
2820
  };
3045
- }, [salesChannelId, topSellerPeriod]);
2821
+ }, [salesChannelId, topSellerPeriod, topSellersLoading, topSellersError, topSellers]);
3046
2822
  react.useEffect(() => {
2823
+ var _a2, _b2;
3047
2824
  let cancelled = false;
2825
+ if (performanceLoading) {
2826
+ setMostViewedTrendLoading(true);
2827
+ return () => {
2828
+ cancelled = true;
2829
+ };
2830
+ }
2831
+ if (performanceError) {
2832
+ setMostViewedTrendLoading(false);
2833
+ setMostViewedTrendError(performanceError);
2834
+ setMostViewedTrend(null);
2835
+ return () => {
2836
+ cancelled = true;
2837
+ };
2838
+ }
2839
+ if (!(performance == null ? void 0 : performance.productViewsConnected)) {
2840
+ setMostViewedTrendLoading(false);
2841
+ setMostViewedTrendError(null);
2842
+ setMostViewedTrend(null);
2843
+ return () => {
2844
+ cancelled = true;
2845
+ };
2846
+ }
2847
+ const topViewedId = (_b2 = (_a2 = performance.topViewedProducts) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.product_id;
2848
+ if (!topViewedId) {
2849
+ setMostViewedTrendLoading(false);
2850
+ setMostViewedTrendError(null);
2851
+ setMostViewedTrend({
2852
+ series: [],
2853
+ productViewsConnected: true,
2854
+ product: null
2855
+ });
2856
+ return () => {
2857
+ cancelled = true;
2858
+ };
2859
+ }
3048
2860
  setMostViewedTrendLoading(true);
3049
2861
  setMostViewedTrendError(null);
3050
2862
  const period = summaryDaysToGraphPeriod(summaryDays);
3051
2863
  fetch(
3052
2864
  buildAnalyticsUrl("/admin/analytics/products-over-time", {
3053
2865
  period,
3054
- sales_channel_id: salesChannelId !== "all" ? salesChannelId : null
2866
+ sales_channel_id: salesChannelId !== "all" ? salesChannelId : null,
2867
+ product_id: topViewedId
3055
2868
  }),
3056
2869
  { credentials: "include" }
3057
2870
  ).then((res) => {
@@ -3069,7 +2882,7 @@ function ProductsDashboard() {
3069
2882
  return () => {
3070
2883
  cancelled = true;
3071
2884
  };
3072
- }, [salesChannelId, summaryDays]);
2885
+ }, [salesChannelId, summaryDays, performanceLoading, performanceError, performance]);
3073
2886
  react.useEffect(() => {
3074
2887
  let cancelled = false;
3075
2888
  setPerformanceLoading(true);
@@ -3115,12 +2928,14 @@ function ProductsDashboard() {
3115
2928
  const viewsConnectedForPulse = ((summary == null ? void 0 : summary.productViewsConnected) ?? false) || (overTime == null ? void 0 : overTime.productViewsConnected) === true || (topSellers == null ? void 0 : topSellers.productViewsConnected) === true || (performance == null ? void 0 : performance.productViewsConnected) === true;
3116
2929
  const bestSellersTrendSeries = (bestSellersTrend == null ? void 0 : bestSellersTrend.series) ?? [];
3117
2930
  const mostViewedTrendSeries = (mostViewedTrend == null ? void 0 : mostViewedTrend.series) ?? [];
2931
+ const bestSellerTrendProductTitle = ((_a = bestSellersTrend == null ? void 0 : bestSellersTrend.product) == null ? void 0 : _a.product_title) ?? ((_c = (_b = topSellers == null ? void 0 : topSellers.products) == null ? void 0 : _b[0]) == null ? void 0 : _c.product_title) ?? null;
2932
+ const mostViewedTrendProductTitle = ((_d = mostViewedTrend == null ? void 0 : mostViewedTrend.product) == null ? void 0 : _d.product_title) ?? ((_f = (_e = performance == null ? void 0 : performance.topViewedProducts) == null ? void 0 : _e[0]) == null ? void 0 : _f.product_title) ?? null;
3118
2933
  const viewsVsUnitsScatterData = react.useMemo(
3119
2934
  () => ((performance == null ? void 0 : performance.topViewedProducts) ?? []).slice(0, 48).filter((row) => row.total_views > 0 || row.units_sold > 0),
3120
2935
  [performance]
3121
2936
  );
3122
- const selectedSummaryPeriod = ((_a = SUMMARY_PERIODS.find((p) => p.value === summaryDays)) == null ? void 0 : _a.label) ?? "All time";
3123
- const selectedGraphPeriodLabel = ((_b = GRAPH_PERIODS.find((p) => p.value === graphPeriod)) == null ? void 0 : _b.label) ?? "One week";
2937
+ const selectedSummaryPeriod = ((_g = SUMMARY_PERIODS.find((p) => p.value === summaryDays)) == null ? void 0 : _g.label) ?? "All time";
2938
+ const selectedGraphPeriodLabel = ((_h = GRAPH_PERIODS.find((p) => p.value === graphPeriod)) == null ? void 0 : _h.label) ?? "One week";
3124
2939
  const quickPulseMetrics = [
3125
2940
  {
3126
2941
  label: "Range units",
@@ -3162,7 +2977,7 @@ function ProductsDashboard() {
3162
2977
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger", children: summaryError ?? "Failed to load product analytics" }) });
3163
2978
  }
3164
2979
  const viewsConnected = summary.productViewsConnected || (overTime == null ? void 0 : overTime.productViewsConnected) === true || (topSellers == null ? void 0 : topSellers.productViewsConnected) === true || (performance == null ? void 0 : performance.productViewsConnected) === true;
3165
- const selectedChannelLabel = salesChannelId === "all" ? "All channels" : ((_c = salesChannels.find((channel) => channel.id === salesChannelId)) == null ? void 0 : _c.name) ?? "Selected channel";
2980
+ const selectedChannelLabel = salesChannelId === "all" ? "All channels" : ((_i = salesChannels.find((channel) => channel.id === salesChannelId)) == null ? void 0 : _i.name) ?? "Selected channel";
3166
2981
  const primaryStats = [
3167
2982
  {
3168
2983
  label: "Units sold",
@@ -3331,9 +3146,9 @@ function ProductsDashboard() {
3331
3146
  }
3332
3147
  )
3333
3148
  ] }),
3334
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
3335
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-1.5 sm:grid-cols-3", children: [
3336
- /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
3149
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
3150
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-3 sm:gap-1.5", children: [
3151
+ /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", className: "min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
3337
3152
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window units" }),
3338
3153
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: formatShortNumber(trendTotals.totalUnits) }),
3339
3154
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-muted text-[10px]", children: [
@@ -3341,7 +3156,7 @@ function ProductsDashboard() {
3341
3156
  trendTotals.avgUnitsPerDay.toFixed(1)
3342
3157
  ] })
3343
3158
  ] }) }),
3344
- /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
3159
+ /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", className: "min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
3345
3160
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window revenue" }),
3346
3161
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: formatCompactCurrency(trendTotals.totalRevenue) }),
3347
3162
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-muted text-[10px]", children: [
@@ -3349,7 +3164,7 @@ function ProductsDashboard() {
3349
3164
  formatCompactCurrency(trendTotals.avgRevenuePerDay)
3350
3165
  ] })
3351
3166
  ] }) }),
3352
- /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
3167
+ /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", className: "min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
3353
3168
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window views" }),
3354
3169
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: formatShortNumber(trendTotals.totalViews) }),
3355
3170
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-muted text-[10px]", children: [
@@ -3358,131 +3173,6 @@ function ProductsDashboard() {
3358
3173
  ] })
3359
3174
  ] }) })
3360
3175
  ] }),
3361
- !overTimeLoading && !overTimeError && series.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-1.5 md:grid-cols-3", children: [
3362
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
3363
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Units sold" }),
3364
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[96px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
3365
- recharts.LineChart,
3366
- {
3367
- data: series,
3368
- margin: { top: 4, right: 4, left: 0, bottom: 0 },
3369
- children: [
3370
- /* @__PURE__ */ jsxRuntime.jsx(
3371
- recharts.CartesianGrid,
3372
- {
3373
- strokeDasharray: "3 3",
3374
- vertical: false,
3375
- stroke: "rgba(148,163,184,0.12)"
3376
- }
3377
- ),
3378
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
3379
- /* @__PURE__ */ jsxRuntime.jsx(
3380
- recharts.YAxis,
3381
- {
3382
- width: 28,
3383
- tick: CHART_AXIS_TICK_SM,
3384
- allowDecimals: false
3385
- }
3386
- ),
3387
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(MiniTrendTooltip, {}) }),
3388
- /* @__PURE__ */ jsxRuntime.jsx(
3389
- recharts.Line,
3390
- {
3391
- type: "natural",
3392
- dataKey: "units_sold",
3393
- name: "Units sold",
3394
- stroke: PRODUCT_CHART_COLORS.units,
3395
- strokeWidth: 2,
3396
- dot: false
3397
- }
3398
- )
3399
- ]
3400
- }
3401
- ) }) })
3402
- ] }),
3403
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
3404
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Views" }),
3405
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[96px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
3406
- recharts.LineChart,
3407
- {
3408
- data: series,
3409
- margin: { top: 4, right: 4, left: 0, bottom: 0 },
3410
- children: [
3411
- /* @__PURE__ */ jsxRuntime.jsx(
3412
- recharts.CartesianGrid,
3413
- {
3414
- strokeDasharray: "3 3",
3415
- vertical: false,
3416
- stroke: "rgba(148,163,184,0.12)"
3417
- }
3418
- ),
3419
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
3420
- /* @__PURE__ */ jsxRuntime.jsx(
3421
- recharts.YAxis,
3422
- {
3423
- width: 28,
3424
- tick: CHART_AXIS_TICK_SM,
3425
- allowDecimals: false
3426
- }
3427
- ),
3428
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(MiniTrendTooltip, {}) }),
3429
- /* @__PURE__ */ jsxRuntime.jsx(
3430
- recharts.Line,
3431
- {
3432
- type: "natural",
3433
- dataKey: "views",
3434
- name: "Views",
3435
- stroke: PRODUCT_CHART_COLORS.views,
3436
- strokeWidth: 2,
3437
- dot: false
3438
- }
3439
- )
3440
- ]
3441
- }
3442
- ) }) })
3443
- ] }),
3444
- /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", children: [
3445
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Revenue" }),
3446
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[96px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
3447
- recharts.LineChart,
3448
- {
3449
- data: series,
3450
- margin: { top: 4, right: 4, left: 0, bottom: 0 },
3451
- children: [
3452
- /* @__PURE__ */ jsxRuntime.jsx(
3453
- recharts.CartesianGrid,
3454
- {
3455
- strokeDasharray: "3 3",
3456
- vertical: false,
3457
- stroke: "rgba(148,163,184,0.12)"
3458
- }
3459
- ),
3460
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
3461
- /* @__PURE__ */ jsxRuntime.jsx(
3462
- recharts.YAxis,
3463
- {
3464
- width: 36,
3465
- tick: CHART_AXIS_TICK_SM,
3466
- tickFormatter: (v) => formatCompactCurrency(Number(v))
3467
- }
3468
- ),
3469
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(MiniTrendTooltip, {}) }),
3470
- /* @__PURE__ */ jsxRuntime.jsx(
3471
- recharts.Line,
3472
- {
3473
- type: "natural",
3474
- dataKey: "revenue",
3475
- name: "Revenue",
3476
- stroke: PRODUCT_CHART_COLORS.revenue,
3477
- strokeWidth: 2,
3478
- dot: false
3479
- }
3480
- )
3481
- ]
3482
- }
3483
- ) }) })
3484
- ] })
3485
- ] }) : null,
3486
3176
  /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", className: "relative overflow-hidden", children: [
3487
3177
  /* @__PURE__ */ jsxRuntime.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" }),
3488
3178
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative space-y-1", children: [
@@ -3708,7 +3398,7 @@ function ProductsDashboard() {
3708
3398
  variant: "atlas",
3709
3399
  actionsBare: true,
3710
3400
  title: "Best sellers",
3711
- description: "Total product revenue over time; bucket length matches the leaderboard window (all-time leaderboard uses a 12-month trend).",
3401
+ description: bestSellerTrendProductTitle ? `Revenue and units over time for “${bestSellerTrendProductTitle}” (#1 by revenue in this window; all-time uses a 12‑month chart).` : "Revenue and units over time for the top product by revenue in this window (all-time leaderboard uses a 12month chart).",
3712
3402
  actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3713
3403
  /* @__PURE__ */ jsxRuntime.jsx(
3714
3404
  ui.Label,
@@ -3784,6 +3474,20 @@ function ProductsDashboard() {
3784
3474
  /* @__PURE__ */ jsxRuntime.jsx(
3785
3475
  recharts.YAxis,
3786
3476
  {
3477
+ yAxisId: "units",
3478
+ tick: CHART_AXIS_TICK_SM,
3479
+ tickFormatter: (value) => formatShortNumber(Number(value)),
3480
+ width: 36,
3481
+ tickLine: false,
3482
+ axisLine: { stroke: CHART_AXIS_LINE },
3483
+ allowDecimals: false
3484
+ }
3485
+ ),
3486
+ /* @__PURE__ */ jsxRuntime.jsx(
3487
+ recharts.YAxis,
3488
+ {
3489
+ yAxisId: "revenue",
3490
+ orientation: "right",
3787
3491
  tick: CHART_AXIS_TICK_SM,
3788
3492
  tickFormatter: (value) => formatCompactCurrency(Number(value)),
3789
3493
  width: 44,
@@ -3791,10 +3495,23 @@ function ProductsDashboard() {
3791
3495
  axisLine: { stroke: CHART_AXIS_LINE }
3792
3496
  }
3793
3497
  ),
3794
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(MiniTrendTooltip, {}) }),
3498
+ /* @__PURE__ */ jsxRuntime.jsx(
3499
+ recharts.Tooltip,
3500
+ {
3501
+ content: (tooltipProps) => /* @__PURE__ */ jsxRuntime.jsx(
3502
+ MiniTrendTooltip,
3503
+ {
3504
+ ...tooltipProps,
3505
+ productHeadline: bestSellerTrendProductTitle,
3506
+ hideViewsRow: true
3507
+ }
3508
+ )
3509
+ }
3510
+ ),
3795
3511
  /* @__PURE__ */ jsxRuntime.jsx(
3796
3512
  recharts.Area,
3797
3513
  {
3514
+ yAxisId: "revenue",
3798
3515
  type: "natural",
3799
3516
  dataKey: "revenue",
3800
3517
  name: "Revenue",
@@ -3806,6 +3523,7 @@ function ProductsDashboard() {
3806
3523
  /* @__PURE__ */ jsxRuntime.jsx(
3807
3524
  recharts.Line,
3808
3525
  {
3526
+ yAxisId: "revenue",
3809
3527
  type: "natural",
3810
3528
  dataKey: "revenue",
3811
3529
  name: "Revenue",
@@ -3815,6 +3533,20 @@ function ProductsDashboard() {
3815
3533
  activeDot: { r: 4, fill: PRODUCT_CHART_COLORS.revenue },
3816
3534
  isAnimationActive: false
3817
3535
  }
3536
+ ),
3537
+ /* @__PURE__ */ jsxRuntime.jsx(
3538
+ recharts.Line,
3539
+ {
3540
+ yAxisId: "units",
3541
+ type: "natural",
3542
+ dataKey: "units_sold",
3543
+ name: "Units sold",
3544
+ stroke: PRODUCT_CHART_COLORS.units,
3545
+ strokeWidth: 2,
3546
+ dot: false,
3547
+ activeDot: { r: 4, fill: PRODUCT_CHART_COLORS.units },
3548
+ isAnimationActive: false
3549
+ }
3818
3550
  )
3819
3551
  ]
3820
3552
  }
@@ -3861,7 +3593,7 @@ function ProductsDashboard() {
3861
3593
  product.product_id
3862
3594
  );
3863
3595
  }) : null,
3864
- !topSellersLoading && !topSellersError && (((_d = topSellers == null ? void 0 : topSellers.products) == null ? void 0 : _d.length) ?? 0) === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
3596
+ !topSellersLoading && !topSellersError && (((_j = topSellers == null ? void 0 : topSellers.products) == null ? void 0 : _j.length) ?? 0) === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
3865
3597
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "No best seller data yet." }) }),
3866
3598
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, {}),
3867
3599
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, {}),
@@ -3877,7 +3609,7 @@ function ProductsDashboard() {
3877
3609
  variant: "atlas",
3878
3610
  className: "min-w-0 md:col-span-1 xl:col-span-1",
3879
3611
  title: "Most viewed products",
3880
- description: "Total product views over time; bucket length follows the summary period (today / 7d → week, 30d → month, 90d / all → year view).",
3612
+ description: mostViewedTrendProductTitle ? `Views over time for “${mostViewedTrendProductTitle}” (top of the list for your summary period; buckets follow period: today / 7d → week, 30d → month, 90d / all → year).` : "Views over time for the most-viewed product in your summary period (buckets: today / 7d → week, 30d → month, 90d / all → year).",
3881
3613
  children: performanceLoading ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-[212px] items-center justify-center sm:h-[228px]", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) }) : performanceError ? /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-[212px] items-center justify-center px-2 sm:h-[228px]", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger text-center text-xs", children: performanceError }) }) }) : !(performance == null ? void 0 : performance.productViewsConnected) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-[212px] sm:min-h-[228px]", children: /* @__PURE__ */ jsxRuntime.jsx(
3882
3614
  EmptyAnalyticsPanel,
3883
3615
  {
@@ -3953,7 +3685,20 @@ function ProductsDashboard() {
3953
3685
  allowDecimals: false
3954
3686
  }
3955
3687
  ),
3956
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(MiniTrendTooltip, {}) }),
3688
+ /* @__PURE__ */ jsxRuntime.jsx(
3689
+ recharts.Tooltip,
3690
+ {
3691
+ content: (tooltipProps) => /* @__PURE__ */ jsxRuntime.jsx(
3692
+ MiniTrendTooltip,
3693
+ {
3694
+ ...tooltipProps,
3695
+ productHeadline: mostViewedTrendProductTitle,
3696
+ hideUnitsRow: true,
3697
+ hideRevenueRow: true
3698
+ }
3699
+ )
3700
+ }
3701
+ ),
3957
3702
  /* @__PURE__ */ jsxRuntime.jsx(
3958
3703
  recharts.Area,
3959
3704
  {
@@ -4004,7 +3749,7 @@ function ProductsDashboard() {
4004
3749
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: product.units_sold.toLocaleString() }),
4005
3750
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: formatRatio(product.views_per_unit) })
4006
3751
  ] }, product.product_id)),
4007
- !performanceLoading && !performanceError && (((_e = performance == null ? void 0 : performance.viewOpportunities) == null ? void 0 : _e.length) ?? 0) === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
3752
+ !performanceLoading && !performanceError && (((_k = performance == null ? void 0 : performance.viewOpportunities) == null ? void 0 : _k.length) ?? 0) === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
4008
3753
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "No product view opportunities yet." }) }),
4009
3754
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, {}),
4010
3755
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, {}),