medusa-analytics 0.0.15 → 0.0.17

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.
@@ -5,61 +5,176 @@ const adminSdk = require("@medusajs/admin-sdk");
5
5
  const icons = require("@medusajs/icons");
6
6
  const ui = require("@medusajs/ui");
7
7
  const recharts = require("recharts");
8
+ const ACCENT_STYLES = {
9
+ blue: {
10
+ border: "border-sky-400/30",
11
+ glow: "shadow-[0_0_0_1px_rgba(56,189,248,0.12),0_18px_40px_-28px_rgba(59,130,246,0.55)]",
12
+ band: "from-sky-400/70 via-blue-400/30 to-transparent"
13
+ },
14
+ purple: {
15
+ border: "border-fuchsia-400/25",
16
+ glow: "shadow-[0_0_0_1px_rgba(217,70,239,0.10),0_18px_40px_-28px_rgba(168,85,247,0.5)]",
17
+ band: "from-fuchsia-400/65 via-violet-400/25 to-transparent"
18
+ },
19
+ green: {
20
+ border: "border-emerald-400/25",
21
+ glow: "shadow-[0_0_0_1px_rgba(52,211,153,0.10),0_18px_40px_-28px_rgba(16,185,129,0.45)]",
22
+ band: "from-emerald-400/65 via-teal-400/25 to-transparent"
23
+ },
24
+ amber: {
25
+ border: "border-amber-400/25",
26
+ glow: "shadow-[0_0_0_1px_rgba(251,191,36,0.10),0_18px_40px_-28px_rgba(245,158,11,0.45)]",
27
+ band: "from-amber-400/65 via-orange-400/25 to-transparent"
28
+ },
29
+ rose: {
30
+ border: "border-rose-400/25",
31
+ glow: "shadow-[0_0_0_1px_rgba(251,113,133,0.10),0_18px_40px_-28px_rgba(244,63,94,0.45)]",
32
+ band: "from-rose-400/65 via-pink-400/25 to-transparent"
33
+ },
34
+ slate: {
35
+ border: "border-ui-border-strong",
36
+ glow: "shadow-[0_0_0_1px_rgba(15,23,42,0.05),0_18px_40px_-28px_rgba(15,23,42,0.22)]",
37
+ band: "from-ui-border-strong via-ui-border-base to-transparent"
38
+ }
39
+ };
40
+ function getAccentStyle(accent) {
41
+ return ACCENT_STYLES[accent];
42
+ }
8
43
  function AnalyticsDashboardShell({ children }) {
9
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children });
44
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2.5 md:space-y-3", children });
10
45
  }
11
46
  function AnalyticsDashboardHeader({
12
47
  title,
13
48
  description,
14
- actions
49
+ actions,
50
+ variant = "default"
15
51
  }) {
16
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "overflow-hidden rounded-2xl border border-ui-border-base bg-ui-bg-base p-0 shadow-sm", children: [
17
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 border-b border-ui-border-base px-5 py-4 xl:flex-row xl:items-start xl:justify-between", children: [
18
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
19
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "tracking-tight", children: title }),
20
- description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: description }) : null
21
- ] }),
22
- actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2 rounded-xl border border-ui-border-base bg-ui-bg-subtle p-2", children: actions }) : null
23
- ] }),
24
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 bg-ui-bg-subtle" })
25
- ] });
26
- }
27
- function AnalyticsStatCard({ label, value, helper }) {
28
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "h-full rounded-2xl border border-ui-border-base bg-ui-bg-base p-4 shadow-sm transition-shadow", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[104px] flex-col justify-between gap-3", children: [
29
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: label }),
30
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "tracking-tight", children: value }),
31
- helper ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: helper }) : null
32
- ] }) });
52
+ const isPremium = variant === "premium";
53
+ return /* @__PURE__ */ jsxRuntime.jsxs(
54
+ ui.Container,
55
+ {
56
+ 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(),
57
+ children: [
58
+ /* @__PURE__ */ jsxRuntime.jsxs(
59
+ "div",
60
+ {
61
+ 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(),
62
+ children: [
63
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
64
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: isPremium ? "text-lg font-semibold tracking-tight" : "tracking-tight", children: title }),
65
+ description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: `text-ui-fg-muted ${isPremium ? "max-w-2xl text-xs leading-snug" : "text-sm"}`.trim(), children: description }) : null
66
+ ] }),
67
+ actions ? /* @__PURE__ */ jsxRuntime.jsx(
68
+ "div",
69
+ {
70
+ 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(),
71
+ children: actions
72
+ }
73
+ ) : null
74
+ ]
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsxRuntime.jsx(
78
+ "div",
79
+ {
80
+ className: `h-px w-full ${isPremium ? "bg-gradient-to-r from-transparent via-ui-border-strong to-transparent" : "bg-ui-bg-subtle"}`.trim()
81
+ }
82
+ )
83
+ ]
84
+ }
85
+ );
33
86
  }
34
- function AnalyticsSection({
35
- title,
36
- description,
37
- actions,
38
- children,
39
- className
87
+ function AnalyticsStatCard({
88
+ label,
89
+ value,
90
+ helper,
91
+ className,
92
+ valueClassName,
93
+ variant = "default",
94
+ accent = "slate"
40
95
  }) {
96
+ const accentStyle = getAccentStyle(accent);
97
+ const isHero = variant === "hero";
98
+ const isCompact = variant === "compact";
41
99
  return /* @__PURE__ */ jsxRuntime.jsxs(
42
100
  ui.Container,
43
101
  {
44
- className: `overflow-hidden rounded-2xl border border-ui-border-base bg-ui-bg-base p-0 shadow-sm ${className ?? ""}`.trim(),
102
+ className: `relative h-full overflow-hidden rounded-2xl border bg-ui-bg-base transition-shadow ${isHero ? `p-3 ${accentStyle.border} ${accentStyle.glow} shadow-sm` : isCompact ? "border-ui-border-base bg-ui-bg-subtle/70 p-2.5 shadow-none" : "border-ui-border-base p-4 shadow-sm"} ${className ?? ""}`.trim(),
45
103
  children: [
46
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-b border-ui-border-base px-5 py-4 lg:flex-row lg:items-start lg:justify-between", children: [
47
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
48
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "tracking-tight", children: title }),
49
- description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: description }) : null
50
- ] }),
51
- actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2 rounded-xl border border-ui-border-base bg-ui-bg-subtle p-2", children: actions }) : null
52
- ] }),
53
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-4", children })
104
+ isHero ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
105
+ /* @__PURE__ */ jsxRuntime.jsx(
106
+ "div",
107
+ {
108
+ className: `pointer-events-none absolute inset-x-3 top-0 h-10 rounded-b-full bg-gradient-to-r ${accentStyle.band} blur-xl`
109
+ }
110
+ ),
111
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-x-3 top-0 h-px bg-gradient-to-r from-transparent via-white/40 to-transparent" })
112
+ ] }) : null,
113
+ /* @__PURE__ */ jsxRuntime.jsxs(
114
+ "div",
115
+ {
116
+ className: `relative flex flex-col justify-between gap-1 ${isCompact ? "min-h-[64px]" : isHero ? "min-h-[72px]" : "min-h-[92px]"}`.trim(),
117
+ children: [
118
+ /* @__PURE__ */ jsxRuntime.jsx(
119
+ ui.Text,
120
+ {
121
+ className: `text-ui-fg-muted font-medium ${isHero ? "text-[10px] uppercase tracking-[0.16em]" : "text-xs"}`.trim(),
122
+ children: label
123
+ }
124
+ ),
125
+ /* @__PURE__ */ jsxRuntime.jsx(
126
+ ui.Heading,
127
+ {
128
+ level: "h2",
129
+ className: `leading-tight tracking-tight ${isHero ? "text-xl sm:text-2xl" : isCompact ? "text-lg" : "text-2xl"} ${valueClassName ?? ""}`.trim(),
130
+ children: value
131
+ }
132
+ ),
133
+ helper ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: `text-ui-fg-muted leading-snug ${isHero ? "text-[10px]" : "text-xs"}`.trim(), children: helper }) : null
134
+ ]
135
+ }
136
+ )
54
137
  ]
55
138
  }
56
139
  );
57
140
  }
58
- function AnalyticsChartSurface({ children, className }) {
141
+ function AnalyticsSection({
142
+ title,
143
+ description,
144
+ actions,
145
+ children,
146
+ className,
147
+ variant = "default"
148
+ }) {
149
+ const isAtlas = variant === "atlas";
150
+ const isPremium = variant !== "default" && !isAtlas;
151
+ 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();
152
+ 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();
153
+ const titleClass = isAtlas ? "text-sm font-semibold tracking-tight text-ui-fg-base" : isPremium ? "text-base font-semibold tracking-tight" : "tracking-tight";
154
+ const descClass = isAtlas ? "max-w-2xl text-[11px] leading-snug text-ui-fg-muted" : isPremium ? "max-w-2xl text-xs leading-snug" : "text-sm";
155
+ 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();
156
+ const bodyClass = isAtlas ? "p-3" : variant === "hero" ? "px-4 py-3" : "px-4 py-3";
157
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: `${shellClass} ${className ?? ""}`.trim(), children: [
158
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: headerClass, children: [
159
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-0.5", children: [
160
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: titleClass, children: title }),
161
+ description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: `text-ui-fg-muted ${descClass}`.trim(), children: description }) : null
162
+ ] }),
163
+ actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: actionsShellClass, children: actions }) : null
164
+ ] }),
165
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: bodyClass, children })
166
+ ] });
167
+ }
168
+ function AnalyticsChartSurface({
169
+ children,
170
+ className,
171
+ variant = "default"
172
+ }) {
173
+ 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";
59
174
  return /* @__PURE__ */ jsxRuntime.jsx(
60
175
  "div",
61
176
  {
62
- className: `rounded-xl border border-ui-border-base bg-ui-bg-subtle p-3 shadow-inner ${className ?? ""}`.trim(),
177
+ className: `${surfaceClassName} ${className ?? ""}`.trim(),
63
178
  children
64
179
  }
65
180
  );
@@ -73,56 +188,174 @@ function AnalyticsTableSurface({ children, className }) {
73
188
  }
74
189
  );
75
190
  }
76
- function OrdersOverTimeTooltip({
77
- active,
78
- payload,
79
- label
191
+ function isDailyOrderRow(value) {
192
+ if (typeof value !== "object" || value === null) return false;
193
+ 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";
194
+ }
195
+ function isOrdersTodayPoint(value) {
196
+ return isDailyOrderRow(value) && "isToday" in value && typeof value.isToday === "boolean";
197
+ }
198
+ function formatCurrency$1(value) {
199
+ return new Intl.NumberFormat("en-IN", {
200
+ style: "currency",
201
+ currency: "INR",
202
+ minimumFractionDigits: 0,
203
+ maximumFractionDigits: 0
204
+ }).format(value);
205
+ }
206
+ function formatCompactCurrency(value) {
207
+ return new Intl.NumberFormat("en-IN", {
208
+ style: "currency",
209
+ currency: "INR",
210
+ notation: "compact",
211
+ maximumFractionDigits: 1
212
+ }).format(value);
213
+ }
214
+ function formatChartLabel(value) {
215
+ if (!value) return "";
216
+ const parsed = new Date(value);
217
+ if (Number.isNaN(parsed.getTime())) return value;
218
+ return `${parsed.getUTCMonth() + 1}/${parsed.getUTCDate()}`;
219
+ }
220
+ function formatPercent(value) {
221
+ return `${value.toFixed(1)}%`;
222
+ }
223
+ function formatShortNumber(value) {
224
+ return new Intl.NumberFormat("en-IN", {
225
+ notation: "compact",
226
+ maximumFractionDigits: value < 10 ? 1 : 0
227
+ }).format(value);
228
+ }
229
+ function TooltipCard({
230
+ title,
231
+ children
80
232
  }) {
81
- var _a, _b;
82
- if (!active || !(payload == null ? void 0 : payload.length)) return null;
83
- const row = (_a = payload[0]) == null ? void 0 : _a.payload;
84
- const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : label);
85
- const value = ((_b = payload[0]) == null ? void 0 : _b.value) ?? 0;
86
233
  return /* @__PURE__ */ jsxRuntime.jsxs(
87
234
  "div",
88
235
  {
89
236
  style: {
90
- backgroundColor: "rgb(250, 234, 234)",
237
+ background: "linear-gradient(180deg, rgba(255,255,255,0.98) 0%, rgba(248,250,252,0.96) 100%)",
91
238
  color: "#111827",
92
- border: "1px solid rgb(229, 231, 235)",
93
- borderRadius: "8px",
94
- padding: "12px 16px",
95
- boxShadow: "0 4px 14px rgba(102, 102, 102, 0.99)",
96
- fontSize: "14px",
97
- lineHeight: 1.5
239
+ border: "1px solid rgba(148, 163, 184, 0.18)",
240
+ borderRadius: "14px",
241
+ padding: "12px 14px",
242
+ boxShadow: "0 16px 40px rgba(15, 23, 42, 0.12)",
243
+ fontSize: "13px",
244
+ lineHeight: 1.5,
245
+ minWidth: "176px"
98
246
  },
99
247
  children: [
100
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, marginBottom: "6px", color: "#111827" }, children: displayLabel }),
101
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "#374151" }, children: [
102
- "Orders: ",
103
- /* @__PURE__ */ jsxRuntime.jsx("strong", { style: { color: "#1f2937" }, children: value })
104
- ] })
248
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, marginBottom: "6px" }, children: title }),
249
+ children
105
250
  ]
106
251
  }
107
252
  );
108
253
  }
109
- const STATUS_COLORS = {
110
- pending: "#F59E0B",
111
- cancelled: "#EF4444",
112
- delivered: "#10B981"
254
+ function OrdersTrendTooltip({
255
+ active,
256
+ payload,
257
+ label
258
+ }) {
259
+ var _a, _b, _c, _d;
260
+ if (!active || !(payload == null ? void 0 : payload.length)) return null;
261
+ const row = isDailyOrderRow((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
262
+ const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : "");
263
+ const orders = ((_c = payload.find((entry) => entry.name === "Orders")) == null ? void 0 : _c.value) ?? 0;
264
+ const revenue = ((_d = payload.find((entry) => entry.name === "Revenue")) == null ? void 0 : _d.value) ?? 0;
265
+ return /* @__PURE__ */ jsxRuntime.jsxs(TooltipCard, { title: displayLabel, children: [
266
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
267
+ "Orders: ",
268
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(orders).toLocaleString() })
269
+ ] }),
270
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
271
+ "Revenue: ",
272
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency$1(Number(revenue)) })
273
+ ] })
274
+ ] });
275
+ }
276
+ function OrdersTodayTooltip({
277
+ active,
278
+ payload,
279
+ label
280
+ }) {
281
+ var _a, _b, _c;
282
+ if (!active || !(payload == null ? void 0 : payload.length)) return null;
283
+ const row = isOrdersTodayPoint((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
284
+ const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : "");
285
+ const orders = ((_c = payload[0]) == null ? void 0 : _c.value) ?? 0;
286
+ return /* @__PURE__ */ jsxRuntime.jsxs(TooltipCard, { title: displayLabel, children: [
287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
288
+ "Orders: ",
289
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(orders).toLocaleString() })
290
+ ] }),
291
+ (row == null ? void 0 : row.isToday) ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#6B7280" }, children: "Current day" }) : null
292
+ ] });
293
+ }
294
+ function OrdersSparklineTooltip({
295
+ active,
296
+ payload,
297
+ label
298
+ }) {
299
+ var _a, _b, _c;
300
+ if (!active || !(payload == null ? void 0 : payload.length)) return null;
301
+ const row = isDailyOrderRow((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
302
+ const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : "");
303
+ const orders = Number((_c = payload[0]) == null ? void 0 : _c.value) || 0;
304
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipCard, { title: displayLabel, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
305
+ "Orders: ",
306
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(orders).toLocaleString() })
307
+ ] }) });
308
+ }
309
+ function OutcomesTrendTooltip({
310
+ active,
311
+ payload,
312
+ label
313
+ }) {
314
+ var _a, _b;
315
+ if (!active || !(payload == null ? void 0 : payload.length)) return null;
316
+ const row = isDailyOrderRow((_a = payload[0]) == null ? void 0 : _a.payload) ? (_b = payload[0]) == null ? void 0 : _b.payload : void 0;
317
+ const displayLabel = (row == null ? void 0 : row.label) ?? (label ? new Date(label).toLocaleDateString() : "");
318
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipCard, { title: displayLabel, children: payload.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
319
+ entry.name,
320
+ ":",
321
+ " ",
322
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(Number(entry.value) || 0).toLocaleString() })
323
+ ] }, String(entry.name))) });
324
+ }
325
+ const KPI_ICON_BG = {
326
+ green: "bg-emerald-500/20",
327
+ blue: "bg-sky-500/20",
328
+ purple: "bg-violet-500/20",
329
+ amber: "bg-amber-500/20"
113
330
  };
114
- const ORDER_CHART_STATUSES = [
115
- { key: "pending", label: "Pending", color: STATUS_COLORS.pending },
116
- { key: "cancelled", label: "Cancelled", color: STATUS_COLORS.cancelled },
117
- { key: "delivered", label: "Delivered", color: STATUS_COLORS.delivered }
118
- ];
119
- function formatCurrency$1(value) {
120
- return new Intl.NumberFormat("en-IN", {
121
- style: "currency",
122
- currency: "INR",
123
- minimumFractionDigits: 0,
124
- maximumFractionDigits: 0
125
- }).format(value);
331
+ function AtlasKpiCard({
332
+ index,
333
+ label,
334
+ value,
335
+ helper,
336
+ accent
337
+ }) {
338
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base p-3 shadow-sm", children: [
339
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
340
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-left text-[11px] leading-tight text-ui-fg-muted", children: [
341
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-ui-fg-base", children: [
342
+ index,
343
+ "."
344
+ ] }),
345
+ " ",
346
+ label
347
+ ] }),
348
+ /* @__PURE__ */ jsxRuntime.jsx(
349
+ "div",
350
+ {
351
+ className: `h-7 w-7 shrink-0 rounded-full ${KPI_ICON_BG[accent]}`,
352
+ "aria-hidden": true
353
+ }
354
+ )
355
+ ] }),
356
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-base font-semibold tabular-nums tracking-tight text-ui-fg-base sm:text-lg", children: value }),
357
+ helper ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mt-1 text-[10px] leading-snug text-ui-fg-muted", children: helper }) : null
358
+ ] });
126
359
  }
127
360
  const SUMMARY_PERIODS$1 = [
128
361
  { value: "all", label: "All time" },
@@ -136,7 +369,34 @@ const OVER_TIME_PERIODS = [
136
369
  { value: "one_month", label: "One month" },
137
370
  { value: "one_year", label: "One year" }
138
371
  ];
372
+ const STATUS_BAR_COLORS = {
373
+ delivered: "#10B981",
374
+ cancelled: "#EF4444",
375
+ exchange: "#F59E0B",
376
+ return: "#8B5CF6",
377
+ today: "var(--medusa-color-ui-fg-interactive)",
378
+ todayMuted: "#BFDBFE",
379
+ orders: "#38BDF8",
380
+ revenue: "#D946EF"
381
+ };
382
+ 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";
383
+ function EmptyAnalyticsPanel({
384
+ title,
385
+ description
386
+ }) {
387
+ return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", className: "h-full", children: /* @__PURE__ */ jsxRuntime.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: [
388
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
389
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-xs font-semibold", children: title }),
390
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[11px] leading-snug", children: description })
391
+ ] }),
392
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-base/80 px-2.5 py-2", children: [
393
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Empty for now" }),
394
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base mt-0.5 text-[11px] leading-snug", children: "Reserved for live analytics when data is available." })
395
+ ] })
396
+ ] }) });
397
+ }
139
398
  function OrdersDashboard() {
399
+ var _a, _b;
140
400
  const [data, setData] = react.useState(null);
141
401
  const [loading, setLoading] = react.useState(true);
142
402
  const [error, setError] = react.useState(null);
@@ -145,12 +405,15 @@ function OrdersDashboard() {
145
405
  const [overTimePeriod, setOverTimePeriod] = react.useState("one_week");
146
406
  const [overTimeLoading, setOverTimeLoading] = react.useState(true);
147
407
  const [overTimeError, setOverTimeError] = react.useState(null);
408
+ const [todayContext, setTodayContext] = react.useState([]);
409
+ const [todayContextLoading, setTodayContextLoading] = react.useState(true);
410
+ const [todayContextError, setTodayContextError] = react.useState(null);
148
411
  react.useEffect(() => {
149
412
  let cancelled = false;
150
413
  setLoading(true);
151
414
  setError(null);
152
415
  const url = `/admin/analytics/orders-summary?days=${filter}`;
153
- fetch(url).then((res) => {
416
+ fetch(url, { credentials: "include" }).then((res) => {
154
417
  if (!res.ok) throw new Error(res.statusText);
155
418
  return res.json();
156
419
  }).then((body) => {
@@ -169,7 +432,7 @@ function OrdersDashboard() {
169
432
  setOverTimeLoading(true);
170
433
  setOverTimeError(null);
171
434
  const url = `/admin/analytics/orders-over-time?period=${overTimePeriod}`;
172
- fetch(url).then((res) => {
435
+ fetch(url, { credentials: "include" }).then((res) => {
173
436
  if (!res.ok) throw new Error(res.statusText);
174
437
  return res.json();
175
438
  }).then((body) => {
@@ -183,11 +446,135 @@ function OrdersDashboard() {
183
446
  cancelled = true;
184
447
  };
185
448
  }, [overTimePeriod]);
449
+ react.useEffect(() => {
450
+ let cancelled = false;
451
+ setTodayContextLoading(true);
452
+ setTodayContextError(null);
453
+ fetch("/admin/analytics/orders-over-time?period=one_week", {
454
+ credentials: "include"
455
+ }).then((res) => {
456
+ if (!res.ok) throw new Error(res.statusText);
457
+ return res.json();
458
+ }).then((body) => {
459
+ if (!cancelled) setTodayContext(body.dailyOrders ?? []);
460
+ }).catch((e) => {
461
+ if (!cancelled) {
462
+ setTodayContextError(e instanceof Error ? e.message : String(e));
463
+ }
464
+ }).finally(() => {
465
+ if (!cancelled) setTodayContextLoading(false);
466
+ });
467
+ return () => {
468
+ cancelled = true;
469
+ };
470
+ }, []);
471
+ const selectedSummaryPeriod = ((_a = SUMMARY_PERIODS$1.find((period) => period.value === filter)) == null ? void 0 : _a.label) ?? "All time";
472
+ const operationsBreakdown = (data == null ? void 0 : data.operationalCounts) ?? {
473
+ cancelled: (data == null ? void 0 : data.cancelledOrders) ?? 0,
474
+ delivered: (data == null ? void 0 : data.deliveredOrders) ?? 0,
475
+ exchange: (data == null ? void 0 : data.exchangeOrders) ?? 0,
476
+ return: (data == null ? void 0 : data.returnOrders) ?? 0
477
+ };
478
+ const outcomesTimeSeriesHasPoints = react.useMemo(
479
+ () => dailyOrders.some(
480
+ (d) => d.delivered_count > 0 || d.cancelled_count > 0 || d.exchange_count > 0 || d.return_count > 0
481
+ ),
482
+ [dailyOrders]
483
+ );
484
+ const totalResolvedOrders = operationsBreakdown.delivered + operationsBreakdown.cancelled;
485
+ const deliveryRate = totalResolvedOrders > 0 ? operationsBreakdown.delivered / totalResolvedOrders * 100 : 0;
486
+ const primaryStats = data ? [
487
+ {
488
+ label: "Total revenue",
489
+ value: formatCurrency$1(data.totalRevenue),
490
+ helper: "Non-cancelled orders",
491
+ accent: "green"
492
+ },
493
+ {
494
+ label: "Total orders",
495
+ value: data.totalOrders.toLocaleString(),
496
+ helper: selectedSummaryPeriod,
497
+ accent: "blue"
498
+ },
499
+ {
500
+ label: "Delivery rate",
501
+ value: formatPercent(deliveryRate),
502
+ helper: "Delivered vs cancelled",
503
+ accent: "purple"
504
+ },
505
+ {
506
+ label: "Average order value",
507
+ value: formatCurrency$1(data.aov),
508
+ helper: "Per non-cancelled order",
509
+ accent: "amber"
510
+ }
511
+ ] : [];
512
+ const secondaryStats = data ? [
513
+ { label: "Orders today", value: data.ordersToday.toLocaleString() },
514
+ { label: "Pending orders", value: data.pendingOrders.toLocaleString() },
515
+ { label: "Delivered orders", value: data.deliveredOrders.toLocaleString() },
516
+ { label: "Cancelled orders", value: data.cancelledOrders.toLocaleString() },
517
+ { label: "Exchange orders", value: data.exchangeOrders.toLocaleString() },
518
+ {
519
+ label: "Avg. fulfillment time",
520
+ value: data.avgFulfillmentTimeHours != null ? `${data.avgFulfillmentTimeHours}h` : "—",
521
+ helper: "Measured in hours"
522
+ }
523
+ ] : [];
524
+ const todayChartData = react.useMemo(
525
+ () => todayContext.map((point, index) => ({
526
+ ...point,
527
+ isToday: index === todayContext.length - 1
528
+ })),
529
+ [todayContext]
530
+ );
531
+ const todayOrdersAverage = todayChartData.length > 0 ? todayChartData.reduce((sum, point) => sum + point.orders_count, 0) / todayChartData.length : 0;
532
+ const todayPoint = todayChartData[todayChartData.length - 1] ?? null;
533
+ const todayDelta = todayPoint && todayOrdersAverage > 0 ? todayPoint.orders_count - todayOrdersAverage : null;
534
+ const trendRevenueTotal = dailyOrders.reduce(
535
+ (sum, point) => sum + point.total_revenue,
536
+ 0
537
+ );
538
+ const trendOrdersTotal = dailyOrders.reduce(
539
+ (sum, point) => sum + point.orders_count,
540
+ 0
541
+ );
542
+ const trendAverageRevenue = dailyOrders.length > 0 ? trendRevenueTotal / dailyOrders.length : 0;
543
+ const trendAverageOrders = dailyOrders.length > 0 ? trendOrdersTotal / dailyOrders.length : 0;
544
+ const peakRevenuePoint = dailyOrders.length > 0 ? dailyOrders.reduce(
545
+ (peak, point) => point.total_revenue > peak.total_revenue ? point : peak
546
+ ) : null;
547
+ const quickPulseMetrics = [
548
+ {
549
+ label: "Range revenue",
550
+ value: formatCompactCurrency(trendRevenueTotal),
551
+ helper: selectedSummaryPeriod,
552
+ accentClassName: "border-emerald-400/25 bg-emerald-500/5"
553
+ },
554
+ {
555
+ label: "Range orders",
556
+ value: formatShortNumber(trendOrdersTotal),
557
+ helper: "Current trend window",
558
+ accentClassName: "border-sky-400/25 bg-sky-500/5"
559
+ },
560
+ {
561
+ label: "Avg/day orders",
562
+ value: trendAverageOrders.toFixed(1),
563
+ helper: "Across selected chart range",
564
+ accentClassName: "border-violet-400/25 bg-violet-500/5"
565
+ },
566
+ {
567
+ label: "Peak revenue day",
568
+ value: peakRevenuePoint ? formatCompactCurrency(peakRevenuePoint.total_revenue) : "—",
569
+ helper: (peakRevenuePoint == null ? void 0 : peakRevenuePoint.label) ?? formatChartLabel(peakRevenuePoint == null ? void 0 : peakRevenuePoint.date),
570
+ accentClassName: "border-amber-400/25 bg-amber-500/5"
571
+ }
572
+ ];
186
573
  if (loading) {
187
574
  return /* @__PURE__ */ jsxRuntime.jsx(
188
575
  "div",
189
576
  {
190
- className: "flex items-center justify-center min-h-[320px]",
577
+ className: "flex min-h-[200px] items-center justify-center",
191
578
  role: "status",
192
579
  "aria-label": "Loading analytics",
193
580
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "Loading…" })
@@ -197,253 +584,656 @@ function OrdersDashboard() {
197
584
  if (error || !data) {
198
585
  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" }) });
199
586
  }
200
- const pieData = ORDER_CHART_STATUSES.map(({ key, label, color }) => {
201
- const value = key === "delivered" ? data.statusCounts.delivered ?? data.deliveredOrders ?? 0 : key === "cancelled" ? data.statusCounts.cancelled ?? data.cancelledOrders ?? 0 : data.statusCounts.pending ?? data.pendingOrders ?? 0;
202
- return { name: label, value, color };
203
- }).filter((d) => d.value > 0);
204
- const returnsExchangesData = [
205
- { name: "Return orders", value: data.returnOrders, color: "#EF4444" },
206
- { name: "Exchange orders", value: data.exchangeOrders, color: "#F59E0B" }
207
- ].filter((d) => d.value > 0);
208
- return /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsDashboardShell, { children: [
587
+ return /* @__PURE__ */ jsxRuntime.jsx(AnalyticsDashboardShell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base/70 bg-ui-bg-subtle/35 p-2 md:p-3", children: [
209
588
  /* @__PURE__ */ jsxRuntime.jsx(
210
589
  AnalyticsDashboardHeader,
211
590
  {
591
+ variant: "premium",
212
592
  title: "Orders",
213
- description: "Monitor revenue, operational health, and status distribution without leaving the analytics workspace.",
214
- actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
215
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
216
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "analytics-period", className: "text-ui-fg-muted text-sm", children: "Period" }),
593
+ description: "Revenue, volume, and outcomes in a compact overview sized for a single viewport.",
594
+ actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-end gap-2.5", children: [
595
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
596
+ /* @__PURE__ */ jsxRuntime.jsx(
597
+ ui.Label,
598
+ {
599
+ htmlFor: "analytics-period",
600
+ className: "text-ui-fg-muted text-xs font-medium",
601
+ children: "Period"
602
+ }
603
+ ),
217
604
  /* @__PURE__ */ jsxRuntime.jsx(
218
605
  "select",
219
606
  {
220
607
  id: "analytics-period",
221
608
  value: filter,
222
609
  onChange: (e) => setFilter(e.target.value),
223
- className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
610
+ className: SELECT_CLASS_NAME,
224
611
  children: SUMMARY_PERIODS$1.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.value, children: p.label }, p.value))
225
612
  }
226
613
  )
227
614
  ] }),
228
- filter !== "all" && /* @__PURE__ */ jsxRuntime.jsx(
615
+ filter !== "all" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center self-end pb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
229
616
  "button",
230
617
  {
231
618
  type: "button",
232
619
  onClick: () => setFilter("all"),
233
- className: "text-xs text-ui-fg-muted hover:text-ui-fg-base transition-colors",
620
+ className: "text-xs text-ui-fg-muted transition-colors hover:text-ui-fg-base",
234
621
  "aria-label": "Show all orders (clear filter)",
235
- children: "Clear filter"
622
+ children: "Clear period"
236
623
  }
237
- )
624
+ ) })
238
625
  ] })
239
626
  }
240
627
  ),
241
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4", children: [
242
- /* @__PURE__ */ jsxRuntime.jsx(
243
- AnalyticsStatCard,
244
- {
245
- label: "Total orders",
246
- value: data.totalOrders.toLocaleString()
247
- }
248
- ),
249
- /* @__PURE__ */ jsxRuntime.jsx(
250
- AnalyticsStatCard,
628
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
629
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Order overview" }) }),
630
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-4", children: primaryStats.map((stat, index) => /* @__PURE__ */ jsxRuntime.jsx(
631
+ AtlasKpiCard,
251
632
  {
252
- label: "Total revenue",
253
- value: formatCurrency$1(data.totalRevenue)
254
- }
255
- ),
256
- /* @__PURE__ */ jsxRuntime.jsx(
257
- AnalyticsStatCard,
633
+ index: index + 1,
634
+ label: stat.label,
635
+ value: stat.value,
636
+ helper: stat.helper,
637
+ accent: stat.accent
638
+ },
639
+ stat.label
640
+ )) })
641
+ ] }),
642
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 grid grid-cols-12 gap-3", children: [
643
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 xl:col-span-6", children: /* @__PURE__ */ jsxRuntime.jsx(
644
+ AnalyticsSection,
258
645
  {
259
- label: "Average order value",
260
- value: formatCurrency$1(data.aov)
646
+ variant: "atlas",
647
+ title: "Revenue & orders",
648
+ description: "Time series for the selected range. Window totals below match this chart.",
649
+ actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
650
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "over-time-period", className: "text-ui-fg-muted text-xs", children: "Range" }),
651
+ /* @__PURE__ */ jsxRuntime.jsx(
652
+ "select",
653
+ {
654
+ id: "over-time-period",
655
+ value: overTimePeriod,
656
+ onChange: (e) => setOverTimePeriod(e.target.value),
657
+ className: SELECT_CLASS_NAME,
658
+ children: OVER_TIME_PERIODS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.value, children: p.label }, p.value))
659
+ }
660
+ )
661
+ ] }),
662
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
663
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-3", children: [
664
+ /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
665
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window revenue" }),
666
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: formatCompactCurrency(trendRevenueTotal) }),
667
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-muted text-[10px]", children: [
668
+ "Avg/day ",
669
+ formatCompactCurrency(trendAverageRevenue)
670
+ ] })
671
+ ] }) }),
672
+ /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
673
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Window orders" }),
674
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-lg font-semibold tracking-tight", children: trendOrdersTotal.toLocaleString() }),
675
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-muted text-[10px]", children: [
676
+ "Avg/day ",
677
+ trendAverageOrders.toFixed(1)
678
+ ] })
679
+ ] }) }),
680
+ /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
681
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Comparison" }),
682
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-sm font-semibold tracking-tight", children: "Last period" }),
683
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] leading-snug", children: "Reserved — API unchanged." })
684
+ ] }) })
685
+ ] }),
686
+ /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", className: "relative overflow-hidden", children: [
687
+ /* @__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" }),
688
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative space-y-2", children: [
689
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
690
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0", children: [
691
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Trend overview" }),
692
+ /* @__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" })
693
+ ] }),
694
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap justify-end gap-2 text-[10px] text-ui-fg-muted", children: [
695
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
696
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-sky-400" }),
697
+ "Orders"
698
+ ] }),
699
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
700
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-fuchsia-400" }),
701
+ "Revenue"
702
+ ] })
703
+ ] })
704
+ ] }),
705
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[min(220px,32vh)] min-h-[180px] sm:h-[min(240px,34vh)]", children: overTimeLoading ? /* @__PURE__ */ jsxRuntime.jsx(
706
+ "div",
707
+ {
708
+ className: "flex h-full items-center justify-center",
709
+ role: "status",
710
+ "aria-label": "Loading orders over time",
711
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading chart…" })
712
+ }
713
+ ) : 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(
714
+ recharts.ComposedChart,
715
+ {
716
+ data: dailyOrders,
717
+ margin: { top: 4, right: 6, left: -6, bottom: 0 },
718
+ children: [
719
+ /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
720
+ /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "ordersGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
721
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#67E8F9" }),
722
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#3B82F6" })
723
+ ] }),
724
+ /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "revenueGradient", x1: "0", y1: "0", x2: "1", y2: "0", children: [
725
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#F472B6" }),
726
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#C084FC" })
727
+ ] }),
728
+ /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "ordersAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
729
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#38BDF8", stopOpacity: 0.22 }),
730
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#38BDF8", stopOpacity: 0 })
731
+ ] }),
732
+ /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "revenueAreaFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
733
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#E879F9", stopOpacity: 0.2 }),
734
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#E879F9", stopOpacity: 0 })
735
+ ] })
736
+ ] }),
737
+ /* @__PURE__ */ jsxRuntime.jsx(
738
+ recharts.CartesianGrid,
739
+ {
740
+ stroke: "rgba(148,163,184,0.14)",
741
+ strokeDasharray: "3 3",
742
+ vertical: false
743
+ }
744
+ ),
745
+ /* @__PURE__ */ jsxRuntime.jsx(
746
+ recharts.XAxis,
747
+ {
748
+ dataKey: "date",
749
+ tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
750
+ tickLine: false,
751
+ axisLine: false,
752
+ tickFormatter: (value, index) => {
753
+ const row = dailyOrders[index];
754
+ return (row == null ? void 0 : row.label) ?? formatChartLabel(value);
755
+ }
756
+ }
757
+ ),
758
+ /* @__PURE__ */ jsxRuntime.jsx(
759
+ recharts.YAxis,
760
+ {
761
+ yAxisId: "orders",
762
+ width: 32,
763
+ tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
764
+ tickLine: false,
765
+ axisLine: false,
766
+ allowDecimals: false,
767
+ tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
768
+ }
769
+ ),
770
+ /* @__PURE__ */ jsxRuntime.jsx(
771
+ recharts.YAxis,
772
+ {
773
+ yAxisId: "revenue",
774
+ orientation: "right",
775
+ width: 40,
776
+ tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
777
+ tickLine: false,
778
+ axisLine: false,
779
+ tickFormatter: (value) => formatCompactCurrency(Number(value) || 0)
780
+ }
781
+ ),
782
+ /* @__PURE__ */ jsxRuntime.jsx(
783
+ recharts.Tooltip,
784
+ {
785
+ content: /* @__PURE__ */ jsxRuntime.jsx(OrdersTrendTooltip, {}),
786
+ cursor: {
787
+ stroke: "rgba(248, 250, 252, 0.35)",
788
+ strokeWidth: 1
789
+ }
790
+ }
791
+ ),
792
+ /* @__PURE__ */ jsxRuntime.jsx(
793
+ recharts.Legend,
794
+ {
795
+ wrapperStyle: { fontSize: 10, paddingTop: 2 },
796
+ iconType: "circle",
797
+ iconSize: 8
798
+ }
799
+ ),
800
+ /* @__PURE__ */ jsxRuntime.jsx(
801
+ recharts.Area,
802
+ {
803
+ yAxisId: "orders",
804
+ type: "natural",
805
+ dataKey: "orders_count",
806
+ stroke: "none",
807
+ fill: "url(#ordersAreaFill)",
808
+ isAnimationActive: false
809
+ }
810
+ ),
811
+ /* @__PURE__ */ jsxRuntime.jsx(
812
+ recharts.Area,
813
+ {
814
+ yAxisId: "revenue",
815
+ type: "natural",
816
+ dataKey: "total_revenue",
817
+ stroke: "none",
818
+ fill: "url(#revenueAreaFill)",
819
+ isAnimationActive: false
820
+ }
821
+ ),
822
+ /* @__PURE__ */ jsxRuntime.jsx(
823
+ recharts.Line,
824
+ {
825
+ yAxisId: "orders",
826
+ type: "natural",
827
+ dataKey: "orders_count",
828
+ name: "Orders",
829
+ stroke: "url(#ordersGradient)",
830
+ strokeWidth: 2,
831
+ dot: false,
832
+ activeDot: { r: 4, fill: STATUS_BAR_COLORS.orders }
833
+ }
834
+ ),
835
+ /* @__PURE__ */ jsxRuntime.jsx(
836
+ recharts.Line,
837
+ {
838
+ yAxisId: "revenue",
839
+ type: "natural",
840
+ dataKey: "total_revenue",
841
+ name: "Revenue",
842
+ stroke: "url(#revenueGradient)",
843
+ strokeWidth: 2,
844
+ dot: false,
845
+ activeDot: { r: 4, fill: STATUS_BAR_COLORS.revenue }
846
+ }
847
+ )
848
+ ]
849
+ }
850
+ ) }) })
851
+ ] })
852
+ ] })
853
+ ] })
261
854
  }
262
- ),
263
- /* @__PURE__ */ jsxRuntime.jsx(
264
- AnalyticsStatCard,
855
+ ) }),
856
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 flex flex-col gap-3 xl:col-span-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
857
+ AnalyticsSection,
265
858
  {
266
- label: "Orders today",
267
- value: data.ordersToday.toLocaleString()
859
+ variant: "atlas",
860
+ title: "Pulse & range",
861
+ description: "Window totals and an orders time series for the selected range.",
862
+ children: [
863
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: quickPulseMetrics.map((metric) => /* @__PURE__ */ jsxRuntime.jsxs(
864
+ "div",
865
+ {
866
+ className: `rounded-lg border border-ui-border-base bg-ui-bg-base px-2 py-2 shadow-sm ${metric.accentClassName}`.trim(),
867
+ children: [
868
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: metric.label }),
869
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base mt-0.5 text-sm font-semibold tracking-tight", children: metric.value }),
870
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted mt-0.5 text-[9px] leading-snug", children: metric.helper })
871
+ ]
872
+ },
873
+ metric.label
874
+ )) }),
875
+ !overTimeLoading && !overTimeError && dailyOrders.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsChartSurface, { variant: "atlas", className: "mt-2", children: [
876
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "mb-1 text-[10px] font-medium uppercase tracking-[0.14em] text-ui-fg-muted", children: "Orders (time series)" }),
877
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[88px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
878
+ recharts.LineChart,
879
+ {
880
+ data: dailyOrders,
881
+ margin: { top: 2, right: 4, left: -18, bottom: 2 },
882
+ children: [
883
+ /* @__PURE__ */ jsxRuntime.jsx(
884
+ recharts.CartesianGrid,
885
+ {
886
+ strokeDasharray: "3 3",
887
+ vertical: false,
888
+ stroke: "rgba(148,163,184,0.12)"
889
+ }
890
+ ),
891
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: "date", hide: true }),
892
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { hide: true, domain: ["auto", "auto"] }),
893
+ /* @__PURE__ */ jsxRuntime.jsx(
894
+ recharts.Tooltip,
895
+ {
896
+ content: /* @__PURE__ */ jsxRuntime.jsx(OrdersSparklineTooltip, {}),
897
+ cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 }
898
+ }
899
+ ),
900
+ /* @__PURE__ */ jsxRuntime.jsx(
901
+ recharts.Line,
902
+ {
903
+ type: "natural",
904
+ dataKey: "orders_count",
905
+ stroke: "#3b82f6",
906
+ strokeWidth: 2,
907
+ dot: { r: 2, fill: "#3b82f6" },
908
+ activeDot: { r: 3 }
909
+ }
910
+ )
911
+ ]
912
+ }
913
+ ) }) })
914
+ ] }) : null
915
+ ]
268
916
  }
269
- ),
270
- /* @__PURE__ */ jsxRuntime.jsx(
917
+ ) }),
918
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 flex flex-col gap-3 xl:col-span-3", children: [
919
+ /* @__PURE__ */ jsxRuntime.jsx(
920
+ AnalyticsSection,
921
+ {
922
+ variant: "atlas",
923
+ title: "Conversion funnel",
924
+ description: "Storefront funnel — connect events to enable this chart.",
925
+ children: /* @__PURE__ */ jsxRuntime.jsx(
926
+ EmptyAnalyticsPanel,
927
+ {
928
+ title: "Visitors to purchase funnel",
929
+ description: "Visitor, product view, cart, checkout, and purchase steps require storefront analytics."
930
+ }
931
+ )
932
+ }
933
+ ),
934
+ /* @__PURE__ */ jsxRuntime.jsx(
935
+ AnalyticsSection,
936
+ {
937
+ variant: "atlas",
938
+ title: "Traffic sources",
939
+ description: "Attribution mix when marketing data is available.",
940
+ children: /* @__PURE__ */ jsxRuntime.jsx(
941
+ EmptyAnalyticsPanel,
942
+ {
943
+ title: "Source mix",
944
+ description: "Channel breakdown (direct, search, social, email) will appear here once connected."
945
+ }
946
+ )
947
+ }
948
+ )
949
+ ] })
950
+ ] }),
951
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 space-y-1.5", children: [
952
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.16em]", children: "Operational signals" }) }),
953
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-3 xl:grid-cols-6", children: secondaryStats.map((stat) => /* @__PURE__ */ jsxRuntime.jsx(
271
954
  AnalyticsStatCard,
272
955
  {
273
- label: "Pending orders",
274
- value: data.pendingOrders.toLocaleString()
275
- }
276
- ),
956
+ label: stat.label,
957
+ value: stat.value,
958
+ helper: stat.helper,
959
+ variant: "compact"
960
+ },
961
+ stat.label
962
+ )) })
963
+ ] }),
964
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-3 xl:grid-cols-12", children: [
277
965
  /* @__PURE__ */ jsxRuntime.jsx(
278
- AnalyticsStatCard,
966
+ AnalyticsSection,
279
967
  {
280
- label: "Avg. fulfillment time",
281
- value: data.avgFulfillmentTimeHours != null ? `${data.avgFulfillmentTimeHours}h` : "—",
282
- helper: "Measured in hours"
968
+ variant: "atlas",
969
+ className: "xl:col-span-7",
970
+ title: "Order outcomes",
971
+ description: "Delivered, cancelled, exchanges, and returns per bucket — same window as Revenue & orders.",
972
+ children: /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[200px] sm:h-[220px]", children: overTimeLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : 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 }) }) : !outcomesTimeSeriesHasPoints ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "No outcome events in this range." }) }) : /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
973
+ recharts.LineChart,
974
+ {
975
+ data: dailyOrders,
976
+ margin: { top: 4, right: 8, left: 0, bottom: 0 },
977
+ children: [
978
+ /* @__PURE__ */ jsxRuntime.jsx(
979
+ recharts.CartesianGrid,
980
+ {
981
+ stroke: "rgba(148,163,184,0.14)",
982
+ strokeDasharray: "3 3",
983
+ vertical: false
984
+ }
985
+ ),
986
+ /* @__PURE__ */ jsxRuntime.jsx(
987
+ recharts.XAxis,
988
+ {
989
+ dataKey: "date",
990
+ tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
991
+ tickLine: false,
992
+ axisLine: false,
993
+ tickFormatter: (value) => {
994
+ const dateStr = typeof value === "string" ? value : String(value);
995
+ const row = dailyOrders.find((d) => d.date === dateStr);
996
+ return (row == null ? void 0 : row.label) ?? formatChartLabel(dateStr);
997
+ }
998
+ }
999
+ ),
1000
+ /* @__PURE__ */ jsxRuntime.jsx(
1001
+ recharts.YAxis,
1002
+ {
1003
+ width: 28,
1004
+ tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
1005
+ tickLine: false,
1006
+ axisLine: false,
1007
+ allowDecimals: false,
1008
+ tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
1009
+ }
1010
+ ),
1011
+ /* @__PURE__ */ jsxRuntime.jsx(
1012
+ recharts.Tooltip,
1013
+ {
1014
+ content: /* @__PURE__ */ jsxRuntime.jsx(OutcomesTrendTooltip, {}),
1015
+ cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 }
1016
+ }
1017
+ ),
1018
+ /* @__PURE__ */ jsxRuntime.jsx(
1019
+ recharts.Legend,
1020
+ {
1021
+ wrapperStyle: { fontSize: 9, paddingTop: 0 },
1022
+ iconType: "circle",
1023
+ iconSize: 6
1024
+ }
1025
+ ),
1026
+ /* @__PURE__ */ jsxRuntime.jsx(
1027
+ recharts.Line,
1028
+ {
1029
+ type: "natural",
1030
+ dataKey: "delivered_count",
1031
+ name: "Delivered",
1032
+ stroke: STATUS_BAR_COLORS.delivered,
1033
+ strokeWidth: 2,
1034
+ dot: false
1035
+ }
1036
+ ),
1037
+ /* @__PURE__ */ jsxRuntime.jsx(
1038
+ recharts.Line,
1039
+ {
1040
+ type: "natural",
1041
+ dataKey: "cancelled_count",
1042
+ name: "Cancelled",
1043
+ stroke: STATUS_BAR_COLORS.cancelled,
1044
+ strokeWidth: 2,
1045
+ dot: false
1046
+ }
1047
+ ),
1048
+ /* @__PURE__ */ jsxRuntime.jsx(
1049
+ recharts.Line,
1050
+ {
1051
+ type: "natural",
1052
+ dataKey: "exchange_count",
1053
+ name: "Exchanges",
1054
+ stroke: STATUS_BAR_COLORS.exchange,
1055
+ strokeWidth: 2,
1056
+ dot: false
1057
+ }
1058
+ ),
1059
+ /* @__PURE__ */ jsxRuntime.jsx(
1060
+ recharts.Line,
1061
+ {
1062
+ type: "natural",
1063
+ dataKey: "return_count",
1064
+ name: "Returns",
1065
+ stroke: STATUS_BAR_COLORS.return,
1066
+ strokeWidth: 2,
1067
+ dot: false
1068
+ }
1069
+ )
1070
+ ]
1071
+ }
1072
+ ) }) }) })
283
1073
  }
284
1074
  ),
285
1075
  /* @__PURE__ */ jsxRuntime.jsx(
286
- AnalyticsStatCard,
1076
+ AnalyticsSection,
287
1077
  {
288
- label: "Cancelled orders",
289
- value: data.cancelledOrders.toLocaleString()
1078
+ variant: "atlas",
1079
+ className: "xl:col-span-5",
1080
+ title: "Recent orders (7 days)",
1081
+ description: "Daily order count vs 7-day average — time series.",
1082
+ children: /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { variant: "atlas", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1083
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1084
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 px-2 py-2", children: [
1085
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Today" }),
1086
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-base font-semibold tracking-tight", children: (todayPoint == null ? void 0 : todayPoint.orders_count.toLocaleString()) ?? "0" })
1087
+ ] }),
1088
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/50 px-2 py-2", children: [
1089
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "7-day avg" }),
1090
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-base text-base font-semibold tracking-tight", children: todayOrdersAverage.toFixed(1) })
1091
+ ] })
1092
+ ] }),
1093
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[160px] sm:h-[180px]", children: todayContextLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "Loading…" }) }) : todayContextError ? /* @__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: todayContextError }) }) : todayChartData.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-xs", children: "No recent activity." }) }) : /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
1094
+ recharts.ComposedChart,
1095
+ {
1096
+ data: todayChartData,
1097
+ margin: { top: 4, right: 4, left: -4, bottom: 0 },
1098
+ children: [
1099
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "todayOrdersFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [
1100
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "#3b82f6", stopOpacity: 0.2 }),
1101
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "#3b82f6", stopOpacity: 0 })
1102
+ ] }) }),
1103
+ /* @__PURE__ */ jsxRuntime.jsx(
1104
+ recharts.CartesianGrid,
1105
+ {
1106
+ stroke: "rgba(148,163,184,0.14)",
1107
+ strokeDasharray: "3 3",
1108
+ vertical: false
1109
+ }
1110
+ ),
1111
+ /* @__PURE__ */ jsxRuntime.jsx(
1112
+ recharts.XAxis,
1113
+ {
1114
+ dataKey: "date",
1115
+ tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
1116
+ tickLine: false,
1117
+ axisLine: false,
1118
+ tickFormatter: formatChartLabel
1119
+ }
1120
+ ),
1121
+ /* @__PURE__ */ jsxRuntime.jsx(
1122
+ recharts.YAxis,
1123
+ {
1124
+ width: 28,
1125
+ tick: { fontSize: 10, fill: "var(--medusa-color-ui-fg-muted)" },
1126
+ tickLine: false,
1127
+ axisLine: false,
1128
+ allowDecimals: false,
1129
+ tickFormatter: (value) => Math.floor(Number(value) || 0).toLocaleString()
1130
+ }
1131
+ ),
1132
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(OrdersTodayTooltip, {}), cursor: { stroke: "rgba(148,163,184,0.35)", strokeWidth: 1 } }),
1133
+ /* @__PURE__ */ jsxRuntime.jsx(
1134
+ recharts.ReferenceLine,
1135
+ {
1136
+ y: todayOrdersAverage,
1137
+ stroke: "rgba(148,163,184,0.65)",
1138
+ strokeDasharray: "4 4"
1139
+ }
1140
+ ),
1141
+ /* @__PURE__ */ jsxRuntime.jsx(
1142
+ recharts.Area,
1143
+ {
1144
+ type: "natural",
1145
+ dataKey: "orders_count",
1146
+ stroke: "none",
1147
+ fill: "url(#todayOrdersFill)",
1148
+ isAnimationActive: false
1149
+ }
1150
+ ),
1151
+ /* @__PURE__ */ jsxRuntime.jsx(
1152
+ recharts.Line,
1153
+ {
1154
+ type: "natural",
1155
+ dataKey: "orders_count",
1156
+ name: "Orders",
1157
+ stroke: "#3b82f6",
1158
+ strokeWidth: 2,
1159
+ dot: (props) => {
1160
+ const { cx, cy, payload } = props;
1161
+ if (payload && typeof payload === "object" && "isToday" in payload && payload.isToday) {
1162
+ return /* @__PURE__ */ jsxRuntime.jsx(
1163
+ "circle",
1164
+ {
1165
+ cx,
1166
+ cy,
1167
+ r: 4,
1168
+ fill: STATUS_BAR_COLORS.today,
1169
+ stroke: "var(--medusa-color-ui-bg-base)",
1170
+ strokeWidth: 1
1171
+ }
1172
+ );
1173
+ }
1174
+ return /* @__PURE__ */ jsxRuntime.jsx("circle", { cx, cy, r: 0, fill: "transparent" });
1175
+ }
1176
+ }
1177
+ )
1178
+ ]
1179
+ }
1180
+ ) }) }),
1181
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle/40 px-2.5 py-2 shadow-sm", children: [
1182
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-[10px] font-medium uppercase tracking-[0.14em]", children: "Note" }),
1183
+ /* @__PURE__ */ jsxRuntime.jsx(ui.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.` })
1184
+ ] })
1185
+ ] }) })
290
1186
  }
291
- ),
1187
+ )
1188
+ ] }),
1189
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 grid grid-cols-1 items-start gap-3 md:grid-cols-3", children: [
292
1190
  /* @__PURE__ */ jsxRuntime.jsx(
293
- AnalyticsStatCard,
1191
+ AnalyticsSection,
294
1192
  {
295
- label: "Delivered orders",
296
- value: data.deliveredOrders.toLocaleString()
1193
+ variant: "atlas",
1194
+ title: "Revenue breakdown",
1195
+ description: "Category or source contribution — time series when connected.",
1196
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1197
+ EmptyAnalyticsPanel,
1198
+ {
1199
+ title: "Stacked breakdown",
1200
+ description: "Connect product or attribution dimensions to show stacked area over time."
1201
+ }
1202
+ )
297
1203
  }
298
1204
  ),
299
1205
  /* @__PURE__ */ jsxRuntime.jsx(
300
- AnalyticsStatCard,
1206
+ AnalyticsSection,
301
1207
  {
302
- label: "Exchange orders",
303
- value: data.exchangeOrders.toLocaleString()
1208
+ variant: "atlas",
1209
+ title: "Cart abandonment",
1210
+ description: "Converted vs abandoned — time series when cart analytics exist.",
1211
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1212
+ EmptyAnalyticsPanel,
1213
+ {
1214
+ title: "Checkout leakage",
1215
+ description: "Donut and trend charts will use cart lifecycle data once available."
1216
+ }
1217
+ )
304
1218
  }
305
1219
  ),
306
1220
  /* @__PURE__ */ jsxRuntime.jsx(
307
- AnalyticsStatCard,
1221
+ AnalyticsSection,
308
1222
  {
309
- label: "Return orders",
310
- value: data.returnOrders.toLocaleString()
311
- }
312
- )
313
- ] }),
314
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 xl:grid-cols-2", children: [
315
- /* @__PURE__ */ jsxRuntime.jsx(AnalyticsSection, { title: "Orders by status", children: /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[300px] items-center justify-center", children: pieData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: 280, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { margin: { top: 8, right: 8, bottom: 8, left: 8 }, children: [
316
- /* @__PURE__ */ jsxRuntime.jsx(
317
- recharts.Pie,
318
- {
319
- data: pieData,
320
- cx: "50%",
321
- cy: "50%",
322
- innerRadius: 52,
323
- outerRadius: 78,
324
- paddingAngle: 2,
325
- dataKey: "value",
326
- nameKey: "name",
327
- isAnimationActive: true,
328
- children: pieData.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Cell, { fill: entry.color }, `cell-${index}`))
329
- }
330
- ),
331
- /* @__PURE__ */ jsxRuntime.jsx(
332
- recharts.Tooltip,
333
- {
334
- formatter: (value) => [value ?? 0, "Orders"]
335
- }
336
- ),
337
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, { verticalAlign: "bottom", height: 36 })
338
- ] }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "No orders in this period" }) }) }) }),
339
- /* @__PURE__ */ jsxRuntime.jsx(AnalyticsSection, { title: "Returns & exchanges", children: /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[300px] items-center justify-center", children: returnsExchangesData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: 280, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { margin: { top: 8, right: 8, bottom: 8, left: 8 }, children: [
340
- /* @__PURE__ */ jsxRuntime.jsx(
341
- recharts.Pie,
342
- {
343
- data: returnsExchangesData,
344
- cx: "50%",
345
- cy: "50%",
346
- innerRadius: 52,
347
- outerRadius: 78,
348
- paddingAngle: 2,
349
- dataKey: "value",
350
- nameKey: "name",
351
- isAnimationActive: true,
352
- children: returnsExchangesData.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Cell, { fill: entry.color }, `cell-re-${index}`))
353
- }
354
- ),
355
- /* @__PURE__ */ jsxRuntime.jsx(
356
- recharts.Tooltip,
357
- {
358
- formatter: (value) => [value ?? 0, "Count"]
359
- }
360
- ),
361
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, { verticalAlign: "bottom", height: 36 })
362
- ] }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "No returns or exchanges in this period" }) }) }) })
363
- ] }),
364
- /* @__PURE__ */ jsxRuntime.jsx(
365
- AnalyticsSection,
366
- {
367
- title: "Orders over time",
368
- actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
369
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "over-time-period", className: "text-ui-fg-muted text-sm", children: "Range" }),
370
- /* @__PURE__ */ jsxRuntime.jsx(
371
- "select",
1223
+ variant: "atlas",
1224
+ title: "Sales by time",
1225
+ description: "Hourly or intraday patterns — bar time series when connected.",
1226
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1227
+ EmptyAnalyticsPanel,
372
1228
  {
373
- id: "over-time-period",
374
- value: overTimePeriod,
375
- onChange: (e) => setOverTimePeriod(e.target.value),
376
- className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
377
- children: OVER_TIME_PERIODS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.value, children: p.label }, p.value))
1229
+ title: "Sales by hour",
1230
+ description: "Order timestamps by hour-of-day will render as a compact bar time series."
378
1231
  }
379
1232
  )
380
- ] }),
381
- children: /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72", children: overTimeLoading ? /* @__PURE__ */ jsxRuntime.jsx(
382
- "div",
383
- {
384
- className: "flex items-center justify-center h-full",
385
- role: "status",
386
- "aria-label": "Loading orders over time",
387
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "Loading chart…" })
388
- }
389
- ) : overTimeError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger", children: overTimeError }) }) : /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
390
- recharts.LineChart,
391
- {
392
- data: dailyOrders,
393
- margin: { top: 8, right: 8, left: 8, bottom: 8 },
394
- children: [
395
- /* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", className: "stroke-ui-border-base" }),
396
- /* @__PURE__ */ jsxRuntime.jsx(
397
- recharts.XAxis,
398
- {
399
- dataKey: "date",
400
- tick: { fontSize: 12 },
401
- tickFormatter: (v, index) => {
402
- const row = dailyOrders[index];
403
- if (row == null ? void 0 : row.label) return row.label;
404
- const d = new Date(v);
405
- return `${d.getUTCMonth() + 1}/${d.getUTCDate()}`;
406
- }
407
- }
408
- ),
409
- /* @__PURE__ */ jsxRuntime.jsx(
410
- recharts.YAxis,
411
- {
412
- tick: { fontSize: 12 },
413
- allowDecimals: false,
414
- domain: [0, "auto"],
415
- ticks: (() => {
416
- const max = Math.max(
417
- 1,
418
- ...dailyOrders.map((d) => d.orders_count ?? 0)
419
- );
420
- const step = max <= 10 ? 1 : Math.ceil(max / 6);
421
- const arr = [];
422
- for (let i = 0; i <= max; i += step) arr.push(i);
423
- if (arr[arr.length - 1] !== max) arr.push(max);
424
- return arr;
425
- })(),
426
- tickFormatter: (v) => String(Math.floor(Number(v) || 0))
427
- }
428
- ),
429
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(OrdersOverTimeTooltip, {}) }),
430
- /* @__PURE__ */ jsxRuntime.jsx(
431
- recharts.Line,
432
- {
433
- type: "monotone",
434
- dataKey: "orders_count",
435
- name: "Orders",
436
- stroke: "var(--medusa-color-ui-fg-interactive)",
437
- strokeWidth: 2,
438
- dot: { r: 3 }
439
- }
440
- )
441
- ]
442
- }
443
- ) }) }) })
444
- }
445
- )
446
- ] });
1233
+ }
1234
+ )
1235
+ ] })
1236
+ ] }) });
447
1237
  }
448
1238
  function CustomersOverTimeTooltip({
449
1239
  active,
@@ -746,6 +1536,7 @@ const TOP_SELLER_PERIODS = [
746
1536
  const SALES_COLOR = "var(--medusa-color-ui-fg-interactive)";
747
1537
  const VIEWS_COLOR = "#8B5CF6";
748
1538
  const REVENUE_COLOR = "#F59E0B";
1539
+ const REVENUE_MUTED_COLOR = "#FCD34D";
749
1540
  function formatCurrency(value) {
750
1541
  return new Intl.NumberFormat("en-IN", {
751
1542
  style: "currency",
@@ -816,7 +1607,8 @@ function TrendTooltip({
816
1607
  }
817
1608
  function ProductBarTooltip({
818
1609
  active,
819
- payload
1610
+ payload,
1611
+ showViews = true
820
1612
  }) {
821
1613
  var _a;
822
1614
  if (!active || !(payload == null ? void 0 : payload.length)) return null;
@@ -844,10 +1636,10 @@ function ProductBarTooltip({
844
1636
  "Units sold: ",
845
1637
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(unitsSold).toLocaleString() })
846
1638
  ] }),
847
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1639
+ showViews ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
848
1640
  "Views: ",
849
1641
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: Math.floor(totalViews).toLocaleString() })
850
- ] }),
1642
+ ] }) : null,
851
1643
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
852
1644
  "Revenue: ",
853
1645
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: formatCurrency(Number(revenue)) })
@@ -1000,10 +1792,14 @@ function ProductsDashboard() {
1000
1792
  };
1001
1793
  }, [salesChannelId, summaryDays]);
1002
1794
  const topSellerChartData = react.useMemo(
1003
- () => ((topSellers == null ? void 0 : topSellers.products) ?? []).slice(0, 7).map((row) => ({
1004
- ...row,
1005
- product_title: truncateLabel(row.product_title, 24)
1006
- })).reverse(),
1795
+ () => ((topSellers == null ? void 0 : topSellers.products) ?? []).slice(0, 7).map((row) => {
1796
+ var _a2, _b2;
1797
+ return {
1798
+ ...row,
1799
+ isBestSeller: row.product_id === (((_b2 = (_a2 = topSellers == null ? void 0 : topSellers.products) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.product_id) ?? null),
1800
+ product_title: truncateLabel(row.product_title, 24)
1801
+ };
1802
+ }).reverse(),
1007
1803
  [topSellers]
1008
1804
  );
1009
1805
  const topViewedChartData = react.useMemo(
@@ -1035,9 +1831,9 @@ function ProductsDashboard() {
1035
1831
  {
1036
1832
  title: "Products",
1037
1833
  description: "Track units sold, revenue, best sellers, and product visit behavior in a denser, easier-to-scan layout.",
1038
- actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1039
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1040
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "products-channel-filter", className: "text-ui-fg-muted text-sm", children: "Channel" }),
1834
+ actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-end gap-2.5", children: [
1835
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1836
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "products-channel-filter", className: "text-ui-fg-muted text-xs font-medium", children: "Channel" }),
1041
1837
  /* @__PURE__ */ jsxRuntime.jsxs(
1042
1838
  "select",
1043
1839
  {
@@ -1045,7 +1841,7 @@ function ProductsDashboard() {
1045
1841
  value: salesChannelId,
1046
1842
  onChange: (event) => setSalesChannelId(event.target.value),
1047
1843
  disabled: filtersLoading,
1048
- className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
1844
+ className: "h-8 min-w-[150px] rounded-md border border-ui-border-base bg-ui-bg-base px-2.5 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
1049
1845
  children: [
1050
1846
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "all", children: "All channels" }),
1051
1847
  salesChannels.map((channel) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: channel.id, children: channel.name }, channel.id))
@@ -1053,39 +1849,41 @@ function ProductsDashboard() {
1053
1849
  }
1054
1850
  )
1055
1851
  ] }),
1056
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1057
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "products-summary-period", className: "text-ui-fg-muted text-sm", children: "Period" }),
1852
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1853
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "products-summary-period", className: "text-ui-fg-muted text-xs font-medium", children: "Period" }),
1058
1854
  /* @__PURE__ */ jsxRuntime.jsx(
1059
1855
  "select",
1060
1856
  {
1061
1857
  id: "products-summary-period",
1062
1858
  value: summaryDays,
1063
1859
  onChange: (event) => setSummaryDays(event.target.value),
1064
- className: "h-9 rounded-md border border-ui-border-base bg-transparent px-3 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
1860
+ className: "h-8 min-w-[132px] rounded-md border border-ui-border-base bg-ui-bg-base px-2.5 text-sm text-ui-fg-base outline-none transition focus:ring-2 focus:ring-ui-fg-interactive",
1065
1861
  children: SUMMARY_PERIODS.map((period) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: period.value, children: period.label }, period.value))
1066
1862
  }
1067
1863
  )
1068
1864
  ] }),
1069
- summaryDays !== "all" && /* @__PURE__ */ jsxRuntime.jsx(
1070
- "button",
1071
- {
1072
- type: "button",
1073
- onClick: () => setSummaryDays("all"),
1074
- className: "text-xs text-ui-fg-muted hover:text-ui-fg-base transition-colors",
1075
- "aria-label": "Show all products analytics",
1076
- children: "Clear filter"
1077
- }
1078
- ),
1079
- salesChannelId !== "all" && /* @__PURE__ */ jsxRuntime.jsx(
1080
- "button",
1081
- {
1082
- type: "button",
1083
- onClick: () => setSalesChannelId("all"),
1084
- className: "text-xs text-ui-fg-muted hover:text-ui-fg-base transition-colors",
1085
- "aria-label": "Show all sales channels",
1086
- children: "Clear channel"
1087
- }
1088
- )
1865
+ (summaryDays !== "all" || salesChannelId !== "all") && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 self-end pb-1", children: [
1866
+ summaryDays !== "all" && /* @__PURE__ */ jsxRuntime.jsx(
1867
+ "button",
1868
+ {
1869
+ type: "button",
1870
+ onClick: () => setSummaryDays("all"),
1871
+ className: "text-xs text-ui-fg-muted transition-colors hover:text-ui-fg-base",
1872
+ "aria-label": "Show all products analytics",
1873
+ children: "Clear period"
1874
+ }
1875
+ ),
1876
+ salesChannelId !== "all" && /* @__PURE__ */ jsxRuntime.jsx(
1877
+ "button",
1878
+ {
1879
+ type: "button",
1880
+ onClick: () => setSalesChannelId("all"),
1881
+ className: "text-xs text-ui-fg-muted transition-colors hover:text-ui-fg-base",
1882
+ "aria-label": "Show all sales channels",
1883
+ children: "Clear channel"
1884
+ }
1885
+ )
1886
+ ] })
1089
1887
  ] })
1090
1888
  }
1091
1889
  ),
@@ -1223,7 +2021,7 @@ function ProductsDashboard() {
1223
2021
  AnalyticsSection,
1224
2022
  {
1225
2023
  title: "Best sellers",
1226
- description: "Ranked by units sold.",
2024
+ description: "Top products by revenue.",
1227
2025
  actions: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: TOP_SELLER_PERIODS.map((period) => /* @__PURE__ */ jsxRuntime.jsx(
1228
2026
  ui.Button,
1229
2027
  {
@@ -1236,7 +2034,14 @@ function ProductsDashboard() {
1236
2034
  )) }),
1237
2035
  children: /* @__PURE__ */ jsxRuntime.jsx(AnalyticsChartSurface, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-80", children: topSellersLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "Loading best sellers…" }) }) : topSellersError || !topSellers ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-danger", children: topSellersError ?? "Failed to load best sellers" }) }) : topSellerChartData.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "No product sales found for this range." }) }) : /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data: topSellerChartData, layout: "vertical", margin: { left: 8, right: 8 }, children: [
1238
2036
  /* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", horizontal: false }),
1239
- /* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { type: "number", allowDecimals: false }),
2037
+ /* @__PURE__ */ jsxRuntime.jsx(
2038
+ recharts.XAxis,
2039
+ {
2040
+ type: "number",
2041
+ allowDecimals: false,
2042
+ tickFormatter: (value) => formatCurrency(Number(value))
2043
+ }
2044
+ ),
1240
2045
  /* @__PURE__ */ jsxRuntime.jsx(
1241
2046
  recharts.YAxis,
1242
2047
  {
@@ -1246,8 +2051,14 @@ function ProductsDashboard() {
1246
2051
  tickLine: false
1247
2052
  }
1248
2053
  ),
1249
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ProductBarTooltip, {}) }),
1250
- /* @__PURE__ */ jsxRuntime.jsx(recharts.Bar, { dataKey: "units_sold", fill: SALES_COLOR, radius: [0, 6, 6, 0] })
2054
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ProductBarTooltip, { showViews: false }) }),
2055
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.Bar, { dataKey: "revenue", radius: [0, 6, 6, 0], children: topSellerChartData.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
2056
+ recharts.Cell,
2057
+ {
2058
+ fill: entry.isBestSeller ? REVENUE_COLOR : REVENUE_MUTED_COLOR
2059
+ },
2060
+ entry.product_id
2061
+ )) })
1251
2062
  ] }) }) }) })
1252
2063
  }
1253
2064
  ),
@@ -1255,7 +2066,7 @@ function ProductsDashboard() {
1255
2066
  AnalyticsSection,
1256
2067
  {
1257
2068
  title: "Top seller breakdown",
1258
- description: "Compact leaderboard for the leading products in the selected period.",
2069
+ description: "Products ranked by revenue.",
1259
2070
  children: /* @__PURE__ */ jsxRuntime.jsx(AnalyticsTableSurface, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
1260
2071
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1261
2072
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Product" }),
@@ -1264,12 +2075,22 @@ function ProductsDashboard() {
1264
2075
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Revenue" })
1265
2076
  ] }) }),
1266
2077
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Body, { children: [
1267
- ((topSellers == null ? void 0 : topSellers.products) ?? []).slice(0, 8).map((product) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1268
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: product.product_title }),
1269
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: product.units_sold.toLocaleString() }),
1270
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: product.order_count.toLocaleString() }),
1271
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: formatCurrency(product.revenue) })
1272
- ] }, product.product_id)),
2078
+ ((topSellers == null ? void 0 : topSellers.products) ?? []).slice(0, 8).map((product) => {
2079
+ var _a2, _b2;
2080
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2081
+ ui.Table.Row,
2082
+ {
2083
+ className: product.product_id === ((_b2 = (_a2 = topSellers == null ? void 0 : topSellers.products) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.product_id) ? "bg-ui-bg-subtle" : void 0,
2084
+ children: [
2085
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: product.product_title }),
2086
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: product.units_sold.toLocaleString() }),
2087
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: product.order_count.toLocaleString() }),
2088
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: formatCurrency(product.revenue) })
2089
+ ]
2090
+ },
2091
+ product.product_id
2092
+ );
2093
+ }),
1273
2094
  !topSellersLoading && (((_b = topSellers == null ? void 0 : topSellers.products) == null ? void 0 : _b.length) ?? 0) === 0 && /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1274
2095
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: "No best seller data yet." }),
1275
2096
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, {}),