medusa-analytics 0.0.2 → 0.0.3
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.
- package/.medusa/server/src/admin/index.js +112 -48
- package/.medusa/server/src/admin/index.mjs +113 -49
- package/.medusa/server/src/api/admin/analytics/orders-over-time/route.js +77 -0
- package/.medusa/server/src/api/admin/analytics/orders-over-time/types.js +7 -0
- package/.medusa/server/src/api/admin/analytics/orders-summary/route.js +14 -25
- package/.medusa/server/src/api/admin/analytics/orders-summary/types.js +2 -1
- package/package.json +1 -1
|
@@ -29,25 +29,32 @@ function formatCurrency(value) {
|
|
|
29
29
|
maximumFractionDigits: 0
|
|
30
30
|
}).format(value);
|
|
31
31
|
}
|
|
32
|
+
const SUMMARY_PERIODS = [
|
|
33
|
+
{ value: "0", label: "Today's orders" },
|
|
34
|
+
{ value: "7", label: "Last 7 days" },
|
|
35
|
+
{ value: "30", label: "Last 30 days" },
|
|
36
|
+
{ value: "90", label: "Last 90 days" }
|
|
37
|
+
];
|
|
38
|
+
const OVER_TIME_PERIODS = [
|
|
39
|
+
{ value: "1d", label: "1 day" },
|
|
40
|
+
{ value: "7d", label: "1 week" },
|
|
41
|
+
{ value: "30d", label: "1 month" }
|
|
42
|
+
];
|
|
32
43
|
function OrdersDashboard() {
|
|
33
44
|
const [data, setData] = react.useState(null);
|
|
34
45
|
const [loading, setLoading] = react.useState(true);
|
|
35
46
|
const [error, setError] = react.useState(null);
|
|
36
47
|
const [filter, setFilter] = react.useState("7");
|
|
48
|
+
const [dailyOrders, setDailyOrders] = react.useState([]);
|
|
49
|
+
const [overTimePeriod, setOverTimePeriod] = react.useState("7d");
|
|
50
|
+
const [overTimeLoading, setOverTimeLoading] = react.useState(true);
|
|
51
|
+
const [overTimeError, setOverTimeError] = react.useState(null);
|
|
37
52
|
react.useEffect(() => {
|
|
38
53
|
let cancelled = false;
|
|
39
54
|
setLoading(true);
|
|
40
55
|
setError(null);
|
|
41
56
|
const url = `/admin/analytics/orders-summary?days=${filter}`;
|
|
42
|
-
if (typeof fetch !== "undefined") {
|
|
43
|
-
fetch("http://127.0.0.1:7242/ingest/47f434f8-0643-48e5-bd1a-edfe05973288", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "21bff8" }, body: JSON.stringify({ sessionId: "21bff8", location: "OrdersDashboard.tsx:useEffect", message: "OrdersDashboard fetch", data: { filter, url }, timestamp: Date.now(), hypothesisId: "C" }) }).catch(() => {
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
57
|
fetch(url).then((res) => {
|
|
47
|
-
if (typeof fetch !== "undefined") {
|
|
48
|
-
fetch("http://127.0.0.1:7242/ingest/47f434f8-0643-48e5-bd1a-edfe05973288", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "21bff8" }, body: JSON.stringify({ sessionId: "21bff8", location: "OrdersDashboard.tsx:fetch.then", message: "API response", data: { status: res.status, statusText: res.statusText, url: res.url }, timestamp: Date.now(), hypothesisId: "C" }) }).catch(() => {
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
58
|
if (!res.ok) throw new Error(res.statusText);
|
|
52
59
|
return res.json();
|
|
53
60
|
}).then((body) => {
|
|
@@ -61,6 +68,25 @@ function OrdersDashboard() {
|
|
|
61
68
|
cancelled = true;
|
|
62
69
|
};
|
|
63
70
|
}, [filter]);
|
|
71
|
+
react.useEffect(() => {
|
|
72
|
+
let cancelled = false;
|
|
73
|
+
setOverTimeLoading(true);
|
|
74
|
+
setOverTimeError(null);
|
|
75
|
+
const url = `/admin/analytics/orders-over-time?period=${overTimePeriod}`;
|
|
76
|
+
fetch(url).then((res) => {
|
|
77
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
78
|
+
return res.json();
|
|
79
|
+
}).then((body) => {
|
|
80
|
+
if (!cancelled) setDailyOrders(body.dailyOrders ?? []);
|
|
81
|
+
}).catch((e) => {
|
|
82
|
+
if (!cancelled) setOverTimeError(e instanceof Error ? e.message : String(e));
|
|
83
|
+
}).finally(() => {
|
|
84
|
+
if (!cancelled) setOverTimeLoading(false);
|
|
85
|
+
});
|
|
86
|
+
return () => {
|
|
87
|
+
cancelled = true;
|
|
88
|
+
};
|
|
89
|
+
}, [overTimePeriod]);
|
|
64
90
|
if (loading) {
|
|
65
91
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
66
92
|
"div",
|
|
@@ -85,24 +111,19 @@ function OrdersDashboard() {
|
|
|
85
111
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-8", children: [
|
|
86
112
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
|
|
87
113
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Orders Analytics" }),
|
|
88
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
114
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
89
115
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "analytics-period", className: "text-ui-fg-muted text-sm", children: "Period" }),
|
|
90
|
-
/* @__PURE__ */ jsxRuntime.
|
|
116
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91
117
|
"select",
|
|
92
118
|
{
|
|
93
119
|
id: "analytics-period",
|
|
94
120
|
value: filter,
|
|
95
121
|
onChange: (e) => setFilter(e.target.value),
|
|
96
122
|
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",
|
|
97
|
-
children:
|
|
98
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "0", children: "Today's orders" }),
|
|
99
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "7", children: "Last 7 days" }),
|
|
100
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "30", children: "Last 30 days" }),
|
|
101
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "90", children: "Last 90 days" })
|
|
102
|
-
]
|
|
123
|
+
children: SUMMARY_PERIODS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.value, children: p.label }, p.value))
|
|
103
124
|
}
|
|
104
125
|
)
|
|
105
|
-
] })
|
|
126
|
+
] }) })
|
|
106
127
|
] }),
|
|
107
128
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4", children: [
|
|
108
129
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-4", children: [
|
|
@@ -133,11 +154,56 @@ function OrdersDashboard() {
|
|
|
133
154
|
] })
|
|
134
155
|
] }),
|
|
135
156
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-6", children: [
|
|
136
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "mb-4", children: "Orders
|
|
137
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
157
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "mb-4", children: "Orders by status" }),
|
|
158
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { children: [
|
|
159
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
160
|
+
recharts.Pie,
|
|
161
|
+
{
|
|
162
|
+
data: pieData,
|
|
163
|
+
cx: "50%",
|
|
164
|
+
cy: "50%",
|
|
165
|
+
innerRadius: 60,
|
|
166
|
+
outerRadius: 100,
|
|
167
|
+
paddingAngle: 2,
|
|
168
|
+
dataKey: "value",
|
|
169
|
+
nameKey: "name",
|
|
170
|
+
label: ({ name, value }) => `${name}: ${value}`,
|
|
171
|
+
children: pieData.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Cell, { fill: entry.color }, `cell-${index}`))
|
|
172
|
+
}
|
|
173
|
+
),
|
|
174
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { formatter: (value) => [value ?? 0, "Orders"] }),
|
|
175
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {})
|
|
176
|
+
] }) }) })
|
|
177
|
+
] }),
|
|
178
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-6", children: [
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 mb-4", children: [
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", children: "Orders over time" }),
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
182
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "over-time-period", className: "text-ui-fg-muted text-sm", children: "Range" }),
|
|
183
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
184
|
+
"select",
|
|
185
|
+
{
|
|
186
|
+
id: "over-time-period",
|
|
187
|
+
value: overTimePeriod,
|
|
188
|
+
onChange: (e) => setOverTimePeriod(e.target.value),
|
|
189
|
+
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",
|
|
190
|
+
children: OVER_TIME_PERIODS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.value, children: p.label }, p.value))
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
] })
|
|
194
|
+
] }),
|
|
195
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72", children: overTimeLoading ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
196
|
+
"div",
|
|
197
|
+
{
|
|
198
|
+
className: "flex items-center justify-center h-full",
|
|
199
|
+
role: "status",
|
|
200
|
+
"aria-label": "Loading orders over time",
|
|
201
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "Loading chart…" })
|
|
202
|
+
}
|
|
203
|
+
) : 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(
|
|
138
204
|
recharts.LineChart,
|
|
139
205
|
{
|
|
140
|
-
data:
|
|
206
|
+
data: dailyOrders,
|
|
141
207
|
margin: { top: 8, right: 8, left: 8, bottom: 8 },
|
|
142
208
|
children: [
|
|
143
209
|
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", className: "stroke-ui-border-base" }),
|
|
@@ -174,28 +240,6 @@ function OrdersDashboard() {
|
|
|
174
240
|
]
|
|
175
241
|
}
|
|
176
242
|
) }) })
|
|
177
|
-
] }),
|
|
178
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-6", children: [
|
|
179
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "mb-4", children: "Orders by status" }),
|
|
180
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { children: [
|
|
181
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
182
|
-
recharts.Pie,
|
|
183
|
-
{
|
|
184
|
-
data: pieData,
|
|
185
|
-
cx: "50%",
|
|
186
|
-
cy: "50%",
|
|
187
|
-
innerRadius: 60,
|
|
188
|
-
outerRadius: 100,
|
|
189
|
-
paddingAngle: 2,
|
|
190
|
-
dataKey: "value",
|
|
191
|
-
nameKey: "name",
|
|
192
|
-
label: ({ name, value }) => `${name}: ${value}`,
|
|
193
|
-
children: pieData.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Cell, { fill: entry.color }, `cell-${index}`))
|
|
194
|
-
}
|
|
195
|
-
),
|
|
196
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { formatter: (value) => [value ?? 0, "Orders"] }),
|
|
197
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {})
|
|
198
|
-
] }) }) })
|
|
199
243
|
] })
|
|
200
244
|
] });
|
|
201
245
|
}
|
|
@@ -203,13 +247,23 @@ const ANALYTICS_MODULES = [{ id: "orders", label: "Orders" }];
|
|
|
203
247
|
const PLUGIN_VERSION = "0.2";
|
|
204
248
|
const AnalyticsPage = () => {
|
|
205
249
|
const [activeModule, setActiveModule] = react.useState("orders");
|
|
206
|
-
|
|
207
|
-
fetch("http://127.0.0.1:7242/ingest/47f434f8-0643-48e5-bd1a-edfe05973288", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "21bff8" }, body: JSON.stringify({ sessionId: "21bff8", location: "page.tsx:AnalyticsPage", message: "Analytics page mounted", data: { pluginVersion: PLUGIN_VERSION, activeModule }, timestamp: Date.now(), hypothesisId: "A" }) }).catch(() => {
|
|
208
|
-
});
|
|
209
|
-
}
|
|
250
|
+
const [sidebarOpen, setSidebarOpen] = react.useState(false);
|
|
210
251
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full bg-ui-bg-base", children: [
|
|
211
|
-
/* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "w-56 shrink-0 border-r border-ui-border-base bg-ui-bg-subtle p-4 flex flex-col", children: [
|
|
212
|
-
/* @__PURE__ */ jsxRuntime.
|
|
252
|
+
sidebarOpen && /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "w-56 shrink-0 border-r border-ui-border-base bg-ui-bg-subtle p-4 flex flex-col relative", children: [
|
|
253
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
254
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "text-ui-fg-subtle", children: "Analysis" }),
|
|
255
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
256
|
+
ui.Button,
|
|
257
|
+
{
|
|
258
|
+
variant: "transparent",
|
|
259
|
+
size: "small",
|
|
260
|
+
className: "shrink-0",
|
|
261
|
+
onClick: () => setSidebarOpen(false),
|
|
262
|
+
"aria-label": "Close sidebar",
|
|
263
|
+
children: "×"
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
] }),
|
|
213
267
|
/* @__PURE__ */ jsxRuntime.jsx("nav", { className: "flex flex-col gap-1 flex-1", children: ANALYTICS_MODULES.map((m) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
214
268
|
ui.Button,
|
|
215
269
|
{
|
|
@@ -225,6 +279,16 @@ const AnalyticsPage = () => {
|
|
|
225
279
|
PLUGIN_VERSION
|
|
226
280
|
] })
|
|
227
281
|
] }),
|
|
282
|
+
!sidebarOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-r border-ui-border-base p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
283
|
+
ui.Button,
|
|
284
|
+
{
|
|
285
|
+
variant: "secondary",
|
|
286
|
+
size: "small",
|
|
287
|
+
onClick: () => setSidebarOpen(true),
|
|
288
|
+
"aria-label": "Show sidebar",
|
|
289
|
+
children: "Analysis"
|
|
290
|
+
}
|
|
291
|
+
) }),
|
|
228
292
|
/* @__PURE__ */ jsxRuntime.jsx("main", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "divide-y p-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 px-6", children: activeModule === "orders" && /* @__PURE__ */ jsxRuntime.jsx(OrdersDashboard, {}) }) }) })
|
|
229
293
|
] });
|
|
230
294
|
};
|
|
@@ -3,7 +3,7 @@ import { useState, useEffect } from "react";
|
|
|
3
3
|
import { defineRouteConfig } from "@medusajs/admin-sdk";
|
|
4
4
|
import { ChartBar } from "@medusajs/icons";
|
|
5
5
|
import { Text, Container, Heading, Label, Button } from "@medusajs/ui";
|
|
6
|
-
import { ResponsiveContainer,
|
|
6
|
+
import { ResponsiveContainer, PieChart, Pie, Cell, Tooltip, Legend, LineChart, CartesianGrid, XAxis, YAxis, Line } from "recharts";
|
|
7
7
|
const STATUS_COLORS = {
|
|
8
8
|
pending: "#F59E0B",
|
|
9
9
|
confirmed: "#3B82F6",
|
|
@@ -28,25 +28,32 @@ function formatCurrency(value) {
|
|
|
28
28
|
maximumFractionDigits: 0
|
|
29
29
|
}).format(value);
|
|
30
30
|
}
|
|
31
|
+
const SUMMARY_PERIODS = [
|
|
32
|
+
{ value: "0", label: "Today's orders" },
|
|
33
|
+
{ value: "7", label: "Last 7 days" },
|
|
34
|
+
{ value: "30", label: "Last 30 days" },
|
|
35
|
+
{ value: "90", label: "Last 90 days" }
|
|
36
|
+
];
|
|
37
|
+
const OVER_TIME_PERIODS = [
|
|
38
|
+
{ value: "1d", label: "1 day" },
|
|
39
|
+
{ value: "7d", label: "1 week" },
|
|
40
|
+
{ value: "30d", label: "1 month" }
|
|
41
|
+
];
|
|
31
42
|
function OrdersDashboard() {
|
|
32
43
|
const [data, setData] = useState(null);
|
|
33
44
|
const [loading, setLoading] = useState(true);
|
|
34
45
|
const [error, setError] = useState(null);
|
|
35
46
|
const [filter, setFilter] = useState("7");
|
|
47
|
+
const [dailyOrders, setDailyOrders] = useState([]);
|
|
48
|
+
const [overTimePeriod, setOverTimePeriod] = useState("7d");
|
|
49
|
+
const [overTimeLoading, setOverTimeLoading] = useState(true);
|
|
50
|
+
const [overTimeError, setOverTimeError] = useState(null);
|
|
36
51
|
useEffect(() => {
|
|
37
52
|
let cancelled = false;
|
|
38
53
|
setLoading(true);
|
|
39
54
|
setError(null);
|
|
40
55
|
const url = `/admin/analytics/orders-summary?days=${filter}`;
|
|
41
|
-
if (typeof fetch !== "undefined") {
|
|
42
|
-
fetch("http://127.0.0.1:7242/ingest/47f434f8-0643-48e5-bd1a-edfe05973288", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "21bff8" }, body: JSON.stringify({ sessionId: "21bff8", location: "OrdersDashboard.tsx:useEffect", message: "OrdersDashboard fetch", data: { filter, url }, timestamp: Date.now(), hypothesisId: "C" }) }).catch(() => {
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
56
|
fetch(url).then((res) => {
|
|
46
|
-
if (typeof fetch !== "undefined") {
|
|
47
|
-
fetch("http://127.0.0.1:7242/ingest/47f434f8-0643-48e5-bd1a-edfe05973288", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "21bff8" }, body: JSON.stringify({ sessionId: "21bff8", location: "OrdersDashboard.tsx:fetch.then", message: "API response", data: { status: res.status, statusText: res.statusText, url: res.url }, timestamp: Date.now(), hypothesisId: "C" }) }).catch(() => {
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
57
|
if (!res.ok) throw new Error(res.statusText);
|
|
51
58
|
return res.json();
|
|
52
59
|
}).then((body) => {
|
|
@@ -60,6 +67,25 @@ function OrdersDashboard() {
|
|
|
60
67
|
cancelled = true;
|
|
61
68
|
};
|
|
62
69
|
}, [filter]);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
let cancelled = false;
|
|
72
|
+
setOverTimeLoading(true);
|
|
73
|
+
setOverTimeError(null);
|
|
74
|
+
const url = `/admin/analytics/orders-over-time?period=${overTimePeriod}`;
|
|
75
|
+
fetch(url).then((res) => {
|
|
76
|
+
if (!res.ok) throw new Error(res.statusText);
|
|
77
|
+
return res.json();
|
|
78
|
+
}).then((body) => {
|
|
79
|
+
if (!cancelled) setDailyOrders(body.dailyOrders ?? []);
|
|
80
|
+
}).catch((e) => {
|
|
81
|
+
if (!cancelled) setOverTimeError(e instanceof Error ? e.message : String(e));
|
|
82
|
+
}).finally(() => {
|
|
83
|
+
if (!cancelled) setOverTimeLoading(false);
|
|
84
|
+
});
|
|
85
|
+
return () => {
|
|
86
|
+
cancelled = true;
|
|
87
|
+
};
|
|
88
|
+
}, [overTimePeriod]);
|
|
63
89
|
if (loading) {
|
|
64
90
|
return /* @__PURE__ */ jsx(
|
|
65
91
|
"div",
|
|
@@ -84,24 +110,19 @@ function OrdersDashboard() {
|
|
|
84
110
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-8", children: [
|
|
85
111
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
|
|
86
112
|
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Orders Analytics" }),
|
|
87
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
88
114
|
/* @__PURE__ */ jsx(Label, { htmlFor: "analytics-period", className: "text-ui-fg-muted text-sm", children: "Period" }),
|
|
89
|
-
/* @__PURE__ */
|
|
115
|
+
/* @__PURE__ */ jsx(
|
|
90
116
|
"select",
|
|
91
117
|
{
|
|
92
118
|
id: "analytics-period",
|
|
93
119
|
value: filter,
|
|
94
120
|
onChange: (e) => setFilter(e.target.value),
|
|
95
121
|
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",
|
|
96
|
-
children:
|
|
97
|
-
/* @__PURE__ */ jsx("option", { value: "0", children: "Today's orders" }),
|
|
98
|
-
/* @__PURE__ */ jsx("option", { value: "7", children: "Last 7 days" }),
|
|
99
|
-
/* @__PURE__ */ jsx("option", { value: "30", children: "Last 30 days" }),
|
|
100
|
-
/* @__PURE__ */ jsx("option", { value: "90", children: "Last 90 days" })
|
|
101
|
-
]
|
|
122
|
+
children: SUMMARY_PERIODS.map((p) => /* @__PURE__ */ jsx("option", { value: p.value, children: p.label }, p.value))
|
|
102
123
|
}
|
|
103
124
|
)
|
|
104
|
-
] })
|
|
125
|
+
] }) })
|
|
105
126
|
] }),
|
|
106
127
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4", children: [
|
|
107
128
|
/* @__PURE__ */ jsxs(Container, { className: "p-4", children: [
|
|
@@ -132,11 +153,56 @@ function OrdersDashboard() {
|
|
|
132
153
|
] })
|
|
133
154
|
] }),
|
|
134
155
|
/* @__PURE__ */ jsxs(Container, { className: "p-6", children: [
|
|
135
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "mb-4", children: "Orders
|
|
136
|
-
/* @__PURE__ */ jsx("div", { className: "h-72", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
|
|
156
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "mb-4", children: "Orders by status" }),
|
|
157
|
+
/* @__PURE__ */ jsx("div", { className: "h-72", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { children: [
|
|
158
|
+
/* @__PURE__ */ jsx(
|
|
159
|
+
Pie,
|
|
160
|
+
{
|
|
161
|
+
data: pieData,
|
|
162
|
+
cx: "50%",
|
|
163
|
+
cy: "50%",
|
|
164
|
+
innerRadius: 60,
|
|
165
|
+
outerRadius: 100,
|
|
166
|
+
paddingAngle: 2,
|
|
167
|
+
dataKey: "value",
|
|
168
|
+
nameKey: "name",
|
|
169
|
+
label: ({ name, value }) => `${name}: ${value}`,
|
|
170
|
+
children: pieData.map((entry, index) => /* @__PURE__ */ jsx(Cell, { fill: entry.color }, `cell-${index}`))
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
/* @__PURE__ */ jsx(Tooltip, { formatter: (value) => [value ?? 0, "Orders"] }),
|
|
174
|
+
/* @__PURE__ */ jsx(Legend, {})
|
|
175
|
+
] }) }) })
|
|
176
|
+
] }),
|
|
177
|
+
/* @__PURE__ */ jsxs(Container, { className: "p-6", children: [
|
|
178
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 mb-4", children: [
|
|
179
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", children: "Orders over time" }),
|
|
180
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
181
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "over-time-period", className: "text-ui-fg-muted text-sm", children: "Range" }),
|
|
182
|
+
/* @__PURE__ */ jsx(
|
|
183
|
+
"select",
|
|
184
|
+
{
|
|
185
|
+
id: "over-time-period",
|
|
186
|
+
value: overTimePeriod,
|
|
187
|
+
onChange: (e) => setOverTimePeriod(e.target.value),
|
|
188
|
+
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",
|
|
189
|
+
children: OVER_TIME_PERIODS.map((p) => /* @__PURE__ */ jsx("option", { value: p.value, children: p.label }, p.value))
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
] })
|
|
193
|
+
] }),
|
|
194
|
+
/* @__PURE__ */ jsx("div", { className: "h-72", children: overTimeLoading ? /* @__PURE__ */ jsx(
|
|
195
|
+
"div",
|
|
196
|
+
{
|
|
197
|
+
className: "flex items-center justify-center h-full",
|
|
198
|
+
role: "status",
|
|
199
|
+
"aria-label": "Loading orders over time",
|
|
200
|
+
children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "Loading chart…" })
|
|
201
|
+
}
|
|
202
|
+
) : overTimeError ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-danger", children: overTimeError }) }) : /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
|
|
137
203
|
LineChart,
|
|
138
204
|
{
|
|
139
|
-
data:
|
|
205
|
+
data: dailyOrders,
|
|
140
206
|
margin: { top: 8, right: 8, left: 8, bottom: 8 },
|
|
141
207
|
children: [
|
|
142
208
|
/* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", className: "stroke-ui-border-base" }),
|
|
@@ -173,28 +239,6 @@ function OrdersDashboard() {
|
|
|
173
239
|
]
|
|
174
240
|
}
|
|
175
241
|
) }) })
|
|
176
|
-
] }),
|
|
177
|
-
/* @__PURE__ */ jsxs(Container, { className: "p-6", children: [
|
|
178
|
-
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "mb-4", children: "Orders by status" }),
|
|
179
|
-
/* @__PURE__ */ jsx("div", { className: "h-72", children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(PieChart, { children: [
|
|
180
|
-
/* @__PURE__ */ jsx(
|
|
181
|
-
Pie,
|
|
182
|
-
{
|
|
183
|
-
data: pieData,
|
|
184
|
-
cx: "50%",
|
|
185
|
-
cy: "50%",
|
|
186
|
-
innerRadius: 60,
|
|
187
|
-
outerRadius: 100,
|
|
188
|
-
paddingAngle: 2,
|
|
189
|
-
dataKey: "value",
|
|
190
|
-
nameKey: "name",
|
|
191
|
-
label: ({ name, value }) => `${name}: ${value}`,
|
|
192
|
-
children: pieData.map((entry, index) => /* @__PURE__ */ jsx(Cell, { fill: entry.color }, `cell-${index}`))
|
|
193
|
-
}
|
|
194
|
-
),
|
|
195
|
-
/* @__PURE__ */ jsx(Tooltip, { formatter: (value) => [value ?? 0, "Orders"] }),
|
|
196
|
-
/* @__PURE__ */ jsx(Legend, {})
|
|
197
|
-
] }) }) })
|
|
198
242
|
] })
|
|
199
243
|
] });
|
|
200
244
|
}
|
|
@@ -202,13 +246,23 @@ const ANALYTICS_MODULES = [{ id: "orders", label: "Orders" }];
|
|
|
202
246
|
const PLUGIN_VERSION = "0.2";
|
|
203
247
|
const AnalyticsPage = () => {
|
|
204
248
|
const [activeModule, setActiveModule] = useState("orders");
|
|
205
|
-
|
|
206
|
-
fetch("http://127.0.0.1:7242/ingest/47f434f8-0643-48e5-bd1a-edfe05973288", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "21bff8" }, body: JSON.stringify({ sessionId: "21bff8", location: "page.tsx:AnalyticsPage", message: "Analytics page mounted", data: { pluginVersion: PLUGIN_VERSION, activeModule }, timestamp: Date.now(), hypothesisId: "A" }) }).catch(() => {
|
|
207
|
-
});
|
|
208
|
-
}
|
|
249
|
+
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
209
250
|
return /* @__PURE__ */ jsxs("div", { className: "flex h-full bg-ui-bg-base", children: [
|
|
210
|
-
/* @__PURE__ */ jsxs("aside", { className: "w-56 shrink-0 border-r border-ui-border-base bg-ui-bg-subtle p-4 flex flex-col", children: [
|
|
211
|
-
/* @__PURE__ */
|
|
251
|
+
sidebarOpen && /* @__PURE__ */ jsxs("aside", { className: "w-56 shrink-0 border-r border-ui-border-base bg-ui-bg-subtle p-4 flex flex-col relative", children: [
|
|
252
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
253
|
+
/* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-ui-fg-subtle", children: "Analysis" }),
|
|
254
|
+
/* @__PURE__ */ jsx(
|
|
255
|
+
Button,
|
|
256
|
+
{
|
|
257
|
+
variant: "transparent",
|
|
258
|
+
size: "small",
|
|
259
|
+
className: "shrink-0",
|
|
260
|
+
onClick: () => setSidebarOpen(false),
|
|
261
|
+
"aria-label": "Close sidebar",
|
|
262
|
+
children: "×"
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
] }),
|
|
212
266
|
/* @__PURE__ */ jsx("nav", { className: "flex flex-col gap-1 flex-1", children: ANALYTICS_MODULES.map((m) => /* @__PURE__ */ jsx(
|
|
213
267
|
Button,
|
|
214
268
|
{
|
|
@@ -224,6 +278,16 @@ const AnalyticsPage = () => {
|
|
|
224
278
|
PLUGIN_VERSION
|
|
225
279
|
] })
|
|
226
280
|
] }),
|
|
281
|
+
!sidebarOpen && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-r border-ui-border-base p-2", children: /* @__PURE__ */ jsx(
|
|
282
|
+
Button,
|
|
283
|
+
{
|
|
284
|
+
variant: "secondary",
|
|
285
|
+
size: "small",
|
|
286
|
+
onClick: () => setSidebarOpen(true),
|
|
287
|
+
"aria-label": "Show sidebar",
|
|
288
|
+
children: "Analysis"
|
|
289
|
+
}
|
|
290
|
+
) }),
|
|
227
291
|
/* @__PURE__ */ jsx("main", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsx(Container, { className: "divide-y p-0", children: /* @__PURE__ */ jsx("div", { className: "py-6 px-6", children: activeModule === "orders" && /* @__PURE__ */ jsx(OrdersDashboard, {}) }) }) })
|
|
228
292
|
] });
|
|
229
293
|
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GET = GET;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const ALLOWED_PERIODS = ["1d", "7d", "30d"];
|
|
6
|
+
function toDateKey(d) {
|
|
7
|
+
return d.toISOString().slice(0, 10);
|
|
8
|
+
}
|
|
9
|
+
function getDaysForPeriod(period) {
|
|
10
|
+
switch (period) {
|
|
11
|
+
case "1d":
|
|
12
|
+
return 1;
|
|
13
|
+
case "7d":
|
|
14
|
+
return 7;
|
|
15
|
+
case "30d":
|
|
16
|
+
return 30;
|
|
17
|
+
default:
|
|
18
|
+
return 7;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function GET(req, res) {
|
|
22
|
+
const remoteQuery = req.scope.resolve(utils_1.ContainerRegistrationKeys.REMOTE_QUERY);
|
|
23
|
+
const periodParam = req.query?.period;
|
|
24
|
+
const period = typeof periodParam === "string" && ALLOWED_PERIODS.includes(periodParam)
|
|
25
|
+
? periodParam
|
|
26
|
+
: "7d";
|
|
27
|
+
const days = getDaysForPeriod(period);
|
|
28
|
+
const today = new Date();
|
|
29
|
+
today.setUTCHours(0, 0, 0, 0);
|
|
30
|
+
const rangeStart = new Date(today);
|
|
31
|
+
rangeStart.setUTCDate(rangeStart.getUTCDate() - (days - 1));
|
|
32
|
+
rangeStart.setUTCHours(0, 0, 0, 0);
|
|
33
|
+
const rangeEnd = new Date(today);
|
|
34
|
+
rangeEnd.setUTCHours(23, 59, 59, 999);
|
|
35
|
+
try {
|
|
36
|
+
const queryObject = (0, utils_1.remoteQueryObjectFromString)({
|
|
37
|
+
entryPoint: "order",
|
|
38
|
+
fields: ["id", "created_at"],
|
|
39
|
+
take: 50000,
|
|
40
|
+
});
|
|
41
|
+
const ordersRaw = await remoteQuery(queryObject);
|
|
42
|
+
const allOrders = Array.isArray(ordersRaw) ? ordersRaw : ordersRaw ? [ordersRaw] : [];
|
|
43
|
+
const dailyMap = {};
|
|
44
|
+
for (const order of allOrders) {
|
|
45
|
+
const o = order;
|
|
46
|
+
const createdAt = o.created_at ? new Date(o.created_at) : null;
|
|
47
|
+
const dateKey = createdAt ? toDateKey(createdAt) : null;
|
|
48
|
+
if (createdAt &&
|
|
49
|
+
dateKey &&
|
|
50
|
+
createdAt >= rangeStart &&
|
|
51
|
+
createdAt <= rangeEnd) {
|
|
52
|
+
dailyMap[dateKey] = (dailyMap[dateKey] ?? 0) + 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const dailyOrders = [];
|
|
56
|
+
for (let i = 0; i < days; i++) {
|
|
57
|
+
const d = new Date(rangeStart);
|
|
58
|
+
d.setUTCDate(d.getUTCDate() + i);
|
|
59
|
+
const key = toDateKey(d);
|
|
60
|
+
dailyOrders.push({
|
|
61
|
+
date: key,
|
|
62
|
+
orders_count: dailyMap[key] ?? 0,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
dailyOrders.sort((a, b) => a.date.localeCompare(b.date));
|
|
66
|
+
const body = { dailyOrders };
|
|
67
|
+
res.json(body);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.error("Orders over time analytics error:", err);
|
|
71
|
+
res.status(500).json({
|
|
72
|
+
error: "Failed to fetch orders over time",
|
|
73
|
+
message: err instanceof Error ? err.message : String(err),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9vcmRlcnMtb3Zlci10aW1lL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBOEJBLGtCQTBFQztBQWxHRCxxREFBa0c7QUFJbEcsTUFBTSxlQUFlLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBVSxDQUFBO0FBR3BELFNBQVMsU0FBUyxDQUFDLENBQU87SUFDeEIsT0FBTyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUNyQyxDQUFDO0FBRUQsU0FBUyxnQkFBZ0IsQ0FBQyxNQUFjO0lBQ3RDLFFBQVEsTUFBTSxFQUFFLENBQUM7UUFDZixLQUFLLElBQUk7WUFDUCxPQUFPLENBQUMsQ0FBQTtRQUNWLEtBQUssSUFBSTtZQUNQLE9BQU8sQ0FBQyxDQUFBO1FBQ1YsS0FBSyxLQUFLO1lBQ1IsT0FBTyxFQUFFLENBQUE7UUFDWDtZQUNFLE9BQU8sQ0FBQyxDQUFBO0lBQ1osQ0FBQztBQUNILENBQUM7QUFFTSxLQUFLLFVBQVUsR0FBRyxDQUN2QixHQUFrQixFQUNsQixHQUFtQjtJQUVuQixNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FDbkMsaUNBQXlCLENBQUMsWUFBWSxDQUN2QyxDQUFBO0lBRUQsTUFBTSxXQUFXLEdBQUcsR0FBRyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUE7SUFDckMsTUFBTSxNQUFNLEdBQ1YsT0FBTyxXQUFXLEtBQUssUUFBUSxJQUFJLGVBQWUsQ0FBQyxRQUFRLENBQUMsV0FBcUIsQ0FBQztRQUNoRixDQUFDLENBQUUsV0FBc0I7UUFDekIsQ0FBQyxDQUFDLElBQUksQ0FBQTtJQUVWLE1BQU0sSUFBSSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFB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
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DTO for GET /admin/analytics/orders-over-time response.
|
|
4
|
+
* Dedicated endpoint for the "Orders over time" chart; real-time data per period (1d, 7d, 30d).
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9vcmRlcnMtb3Zlci10aW1lL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O0dBR0cifQ==
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GET = GET;
|
|
4
4
|
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
/** Status buckets used for Orders by status pie chart */
|
|
5
6
|
const STATUS_BUCKETS = [
|
|
6
7
|
"pending",
|
|
7
8
|
"confirmed",
|
|
@@ -35,12 +36,10 @@ async function GET(req, res) {
|
|
|
35
36
|
? Number(daysParam)
|
|
36
37
|
: 7;
|
|
37
38
|
const days = daysInput === 0 ? 1 : daysInput;
|
|
38
|
-
// #region agent log
|
|
39
|
-
fetch('http://127.0.0.1:7242/ingest/47f434f8-0643-48e5-bd1a-edfe05973288', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Debug-Session-Id': '21bff8' }, body: JSON.stringify({ sessionId: '21bff8', location: 'orders-summary/route.ts:GET', message: 'orders-summary GET hit', data: { daysParam, daysInput, days }, timestamp: Date.now(), hypothesisId: 'C' }) }).catch(() => { });
|
|
40
|
-
// #endregion
|
|
41
39
|
const today = new Date();
|
|
42
40
|
today.setUTCHours(0, 0, 0, 0);
|
|
43
41
|
const todayKey = toDateKey(today);
|
|
42
|
+
// Date range for KPIs and status counts (days param: 0 = today, 7/30/90 = last N days)
|
|
44
43
|
const rangeStart = new Date(today);
|
|
45
44
|
rangeStart.setUTCDate(rangeStart.getUTCDate() - (days - 1));
|
|
46
45
|
rangeStart.setUTCHours(0, 0, 0, 0);
|
|
@@ -65,10 +64,12 @@ async function GET(req, res) {
|
|
|
65
64
|
for (const key of STATUS_BUCKETS) {
|
|
66
65
|
statusCounts[key] = 0;
|
|
67
66
|
}
|
|
67
|
+
// Revenue and AOV exclude cancelled orders; totalOrders KPI counts all orders in range
|
|
68
68
|
let totalRevenue = 0;
|
|
69
|
+
let nonCancelledCount = 0;
|
|
69
70
|
let ordersTodayCount = 0;
|
|
70
71
|
let pendingOrders = 0;
|
|
71
|
-
|
|
72
|
+
let totalOrders = 0;
|
|
72
73
|
const fulfillmentTimesMs = [];
|
|
73
74
|
for (const order of allOrders) {
|
|
74
75
|
const o = order;
|
|
@@ -83,15 +84,17 @@ async function GET(req, res) {
|
|
|
83
84
|
const status = o.status;
|
|
84
85
|
const normalized = normalizeStatus(status);
|
|
85
86
|
statusCounts[normalized] = (statusCounts[normalized] ?? 0) + 1;
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
totalOrders += 1;
|
|
88
|
+
// Total revenue and AOV: only include non-cancelled orders
|
|
89
|
+
if (normalized !== "cancelled") {
|
|
90
|
+
const total = typeof o.total === "number" ? o.total : 0;
|
|
91
|
+
totalRevenue += total;
|
|
92
|
+
nonCancelledCount += 1;
|
|
93
|
+
}
|
|
88
94
|
if (dateKey === todayKey)
|
|
89
95
|
ordersTodayCount += 1;
|
|
90
96
|
if (isPendingStatus(status))
|
|
91
97
|
pendingOrders += 1;
|
|
92
|
-
if (dateKey) {
|
|
93
|
-
dailyMap[dateKey] = (dailyMap[dateKey] ?? 0) + 1;
|
|
94
|
-
}
|
|
95
98
|
const fulfillments = o.fulfillments ?? [];
|
|
96
99
|
for (const f of fulfillments) {
|
|
97
100
|
const shippedAt = f.shipped_at ? new Date(f.shipped_at) : null;
|
|
@@ -101,20 +104,7 @@ async function GET(req, res) {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
|
-
const
|
|
105
|
-
const aov = totalOrders > 0 ? totalRevenue / totalOrders : 0;
|
|
106
|
-
const dayCount = daysInput === 0 ? 1 : days;
|
|
107
|
-
const dailyOrders = [];
|
|
108
|
-
for (let i = 0; i < dayCount; i++) {
|
|
109
|
-
const d = new Date(rangeStart);
|
|
110
|
-
d.setUTCDate(d.getUTCDate() + i);
|
|
111
|
-
const key = toDateKey(d);
|
|
112
|
-
dailyOrders.push({
|
|
113
|
-
date: key,
|
|
114
|
-
orders_count: dailyMap[key] ?? 0,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
dailyOrders.sort((a, b) => a.date.localeCompare(b.date));
|
|
107
|
+
const aov = nonCancelledCount > 0 ? totalRevenue / nonCancelledCount : 0;
|
|
118
108
|
let avgFulfillmentTimeHours = null;
|
|
119
109
|
if (fulfillmentTimesMs.length > 0) {
|
|
120
110
|
const avgMs = fulfillmentTimesMs.reduce((s, t) => s + t, 0) / fulfillmentTimesMs.length;
|
|
@@ -128,7 +118,6 @@ async function GET(req, res) {
|
|
|
128
118
|
pendingOrders,
|
|
129
119
|
avgFulfillmentTimeHours,
|
|
130
120
|
statusCounts,
|
|
131
|
-
dailyOrders,
|
|
132
121
|
};
|
|
133
122
|
res.json(body);
|
|
134
123
|
}
|
|
@@ -140,4 +129,4 @@ async function GET(req, res) {
|
|
|
140
129
|
});
|
|
141
130
|
}
|
|
142
131
|
}
|
|
143
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
132
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9vcmRlcnMtc3VtbWFyeS9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXFDQSxrQkFrSUM7QUFqS0QscURBQWtHO0FBSWxHLHlEQUF5RDtBQUN6RCxNQUFNLGNBQWMsR0FBRztJQUNyQixTQUFTO0lBQ1QsV0FBVztJQUNYLFlBQVk7SUFDWixTQUFTO0lBQ1QsV0FBVztJQUNYLFdBQVc7Q0FDSCxDQUFBO0FBRVYsU0FBUyxlQUFlLENBQUMsTUFBMEI7SUFDakQsSUFBSSxDQUFDLE1BQU0sSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRO1FBQUUsT0FBTyxTQUFTLENBQUE7SUFDM0QsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFBO0lBQzlCLElBQUksQ0FBQyxLQUFLLFVBQVUsSUFBSSxDQUFDLEtBQUssV0FBVztRQUFFLE9BQU8sV0FBVyxDQUFBO0lBQzdELElBQUksY0FBYyxDQUFDLFFBQVEsQ0FBQyxDQUFvQyxDQUFDO1FBQUUsT0FBTyxDQUFvQyxDQUFBO0lBQzlHLE9BQU8sU0FBUyxDQUFBO0FBQ2xCLENBQUM7QUFFRCxTQUFTLGVBQWUsQ0FBQyxNQUEwQjtJQUNqRCxNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDMUMsT0FBTyxVQUFVLEtBQUssV0FBVyxJQUFJLFVBQVUsS0FBSyxXQUFXLENBQUE7QUFDakUsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLENBQU87SUFDeEIsT0FBTyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUNyQyxDQUFDO0FBRU0sS0FBSyxVQUFVLEdBQUcsQ0FDdkIsR0FBa0IsRUFDbEIsR0FBbUI7SUFFbkIsTUFBTSxXQUFXLEdBQUcsR0FBRyxDQUFD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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* DTO for GET /admin/analytics/orders-summary response.
|
|
4
|
+
* KPI cards and order-by-status only; for orders-over-time series use the orders-over-time API.
|
|
4
5
|
*/
|
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2FuYWx5dGljcy9vcmRlcnMtc3VtbWFyeS90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztHQUdHIn0=
|