@agilo/medusa-analytics-plugin 1.0.0 → 1.1.0
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 +329 -282
- package/.medusa/server/src/admin/index.mjs +331 -284
- package/package.json +3 -2
|
@@ -7,10 +7,10 @@ const icons = require("@medusajs/icons");
|
|
|
7
7
|
const lucideReact = require("lucide-react");
|
|
8
8
|
const dateFns = require("date-fns");
|
|
9
9
|
const reactAriaComponents = require("react-aria-components");
|
|
10
|
+
const reactRouterDom = require("react-router-dom");
|
|
10
11
|
const recharts = require("recharts");
|
|
11
12
|
const clsx = require("clsx");
|
|
12
13
|
const tailwindMerge = require("tailwind-merge");
|
|
13
|
-
const reactRouterDom = require("react-router-dom");
|
|
14
14
|
const reactQuery = require("@tanstack/react-query");
|
|
15
15
|
function _interopNamespace(e) {
|
|
16
16
|
if (e && e.__esModule) return e;
|
|
@@ -675,68 +675,65 @@ const LineChart = ({
|
|
|
675
675
|
const isDark = useDarkMode();
|
|
676
676
|
const isSingleDataPoint = data && data.length === 1;
|
|
677
677
|
if (isSingleDataPoint) {
|
|
678
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
679
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
{
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
fontWeight: "500",
|
|
725
|
-
marginBottom: "4px"
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
),
|
|
729
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
730
|
-
recharts.Bar,
|
|
731
|
-
{
|
|
732
|
-
dataKey: yAxisDataKey,
|
|
733
|
-
fill: lineColor,
|
|
734
|
-
radius: [4, 4, 0, 0],
|
|
735
|
-
maxBarSize: 60
|
|
678
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { aspect: 16 / 9, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data, margin: { left: 20 }, children: [
|
|
679
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
680
|
+
recharts.CartesianGrid,
|
|
681
|
+
{
|
|
682
|
+
strokeDasharray: "3 3",
|
|
683
|
+
stroke: isDark ? "#374151" : "#E5E7EB"
|
|
684
|
+
}
|
|
685
|
+
),
|
|
686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
687
|
+
recharts.XAxis,
|
|
688
|
+
{
|
|
689
|
+
dataKey: xAxisDataKey,
|
|
690
|
+
tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
|
|
691
|
+
axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
|
|
692
|
+
tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
|
|
693
|
+
tickMargin: 10
|
|
694
|
+
}
|
|
695
|
+
),
|
|
696
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
697
|
+
recharts.YAxis,
|
|
698
|
+
{
|
|
699
|
+
tickFormatter: yAxisTickFormatter,
|
|
700
|
+
allowDecimals: false,
|
|
701
|
+
tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
|
|
702
|
+
axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
|
|
703
|
+
tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" }
|
|
704
|
+
}
|
|
705
|
+
),
|
|
706
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
707
|
+
recharts.Tooltip,
|
|
708
|
+
{
|
|
709
|
+
cursor: {
|
|
710
|
+
fill: isDark ? "rgba(55, 65, 81, 0.2)" : "rgba(243, 244, 246, 0.5)"
|
|
711
|
+
},
|
|
712
|
+
formatter: (value) => yAxisTickFormatter ? yAxisTickFormatter(value) : value,
|
|
713
|
+
contentStyle: {
|
|
714
|
+
backgroundColor: isDark ? "#1F2937" : "#FFFFFF",
|
|
715
|
+
border: `1px solid ${isDark ? "#374151" : "#E5E7EB"}`,
|
|
716
|
+
borderRadius: "0.5rem",
|
|
717
|
+
color: isDark ? "#F9FAFB" : "#111827",
|
|
718
|
+
boxShadow: isDark ? "0 4px 6px -1px rgba(0, 0, 0, 0.3)" : "0 4px 6px -1px rgba(0, 0, 0, 0.1)"
|
|
719
|
+
},
|
|
720
|
+
labelStyle: {
|
|
721
|
+
color: isDark ? "#F9FAFB" : "#111827",
|
|
722
|
+
fontWeight: "500",
|
|
723
|
+
marginBottom: "4px"
|
|
736
724
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
725
|
+
}
|
|
726
|
+
),
|
|
727
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
728
|
+
recharts.Bar,
|
|
729
|
+
{
|
|
730
|
+
dataKey: yAxisDataKey,
|
|
731
|
+
fill: lineColor,
|
|
732
|
+
radius: [4, 4, 0, 0],
|
|
733
|
+
maxBarSize: 60
|
|
734
|
+
}
|
|
735
|
+
)
|
|
736
|
+
] }) }) });
|
|
740
737
|
}
|
|
741
738
|
return /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { aspect: 16 / 9, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, margin: { left: 20 }, children: [
|
|
742
739
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1075,7 +1072,7 @@ const ProductsTable = ({ products }) => {
|
|
|
1075
1072
|
products.length > PAGE_SIZE && /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
|
|
1076
1073
|
] });
|
|
1077
1074
|
};
|
|
1078
|
-
const BACKEND_URL$1 =
|
|
1075
|
+
const BACKEND_URL$1 = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
|
|
1079
1076
|
async function retrieveProductAnalytics(date) {
|
|
1080
1077
|
if (!date || !date.from || !(date == null ? void 0 : date.to)) {
|
|
1081
1078
|
return void 0;
|
|
@@ -1098,7 +1095,7 @@ const useProductAnalytics = (query, options) => {
|
|
|
1098
1095
|
...options
|
|
1099
1096
|
});
|
|
1100
1097
|
};
|
|
1101
|
-
const BACKEND_URL =
|
|
1098
|
+
const BACKEND_URL = __BACKEND_URL__ === "/" ? "" : __BACKEND_URL__;
|
|
1102
1099
|
async function retrieveOrderAnalytics(preset, date) {
|
|
1103
1100
|
if (!date || !date.from || !(date == null ? void 0 : date.to)) {
|
|
1104
1101
|
const data2 = await fetch(
|
|
@@ -1242,16 +1239,39 @@ function rangeValueToDateRange(rangeValue) {
|
|
|
1242
1239
|
to: rangeValue.end ? calendarDateToDate(rangeValue.end) : void 0
|
|
1243
1240
|
};
|
|
1244
1241
|
}
|
|
1242
|
+
function presetToDateRange(preset) {
|
|
1243
|
+
const today = /* @__PURE__ */ new Date();
|
|
1244
|
+
if (preset === "this-month") return { from: dateFns.startOfMonth(today), to: today };
|
|
1245
|
+
if (preset === "last-month")
|
|
1246
|
+
return {
|
|
1247
|
+
from: dateFns.startOfMonth(dateFns.subMonths(today, 1)),
|
|
1248
|
+
to: dateFns.endOfMonth(dateFns.subMonths(today, 1))
|
|
1249
|
+
};
|
|
1250
|
+
return {
|
|
1251
|
+
from: dateFns.startOfMonth(dateFns.subMonths(today, 3)),
|
|
1252
|
+
to: dateFns.endOfMonth(dateFns.subMonths(today, 1))
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
const DATE_RANGE_REGEX = /^(\d{4}-\d{2}-\d{2})-(\d{4}-\d{2}-\d{2})$/;
|
|
1245
1256
|
const AnalyticsPage = () => {
|
|
1246
1257
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1247
|
-
const [
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1258
|
+
const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
|
|
1259
|
+
const rangeParam = searchParams.get("range") || "this-month";
|
|
1260
|
+
const date = React__namespace.useMemo(() => {
|
|
1261
|
+
if (rangeParam === "this-month" || rangeParam === "last-month" || rangeParam === "last-3-months") {
|
|
1262
|
+
return presetToDateRange(rangeParam);
|
|
1263
|
+
}
|
|
1264
|
+
const dates = rangeParam.match(DATE_RANGE_REGEX);
|
|
1265
|
+
if (dates) {
|
|
1266
|
+
const from = dateFns.parse(dates[1], "yyyy-MM-dd", /* @__PURE__ */ new Date());
|
|
1267
|
+
const to = dateFns.parse(dates[2], "yyyy-MM-dd", /* @__PURE__ */ new Date());
|
|
1268
|
+
return { from, to };
|
|
1269
|
+
}
|
|
1270
|
+
return void 0;
|
|
1271
|
+
}, [rangeParam]);
|
|
1252
1272
|
const { data: products, isLoading: isLoadingProducts } = useProductAnalytics(date);
|
|
1253
1273
|
const { data: orders, isLoading: isLoadingOrders } = useOrderAnalytics(
|
|
1254
|
-
|
|
1274
|
+
["this-month", "last-month", "last-3-months"].includes(rangeParam) ? rangeParam : "custom",
|
|
1255
1275
|
date
|
|
1256
1276
|
);
|
|
1257
1277
|
const someOrderCountsGreaterThanZero = (_a = orders == null ? void 0 : orders.order_count) == null ? void 0 : _a.some(
|
|
@@ -1261,45 +1281,59 @@ const AnalyticsPage = () => {
|
|
|
1261
1281
|
(item) => item.sales > 0
|
|
1262
1282
|
);
|
|
1263
1283
|
const someTopSellingProductsGreaterThanZero = (_c = products == null ? void 0 : products.variantQuantitySold) == null ? void 0 : _c.some((item) => item.quantity > 0);
|
|
1264
|
-
const updateDatePreset = React__namespace.useCallback(
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1284
|
+
const updateDatePreset = React__namespace.useCallback(
|
|
1285
|
+
(preset) => {
|
|
1286
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1287
|
+
switch (preset) {
|
|
1288
|
+
case "this-month":
|
|
1289
|
+
params.set("range", "this-month");
|
|
1290
|
+
break;
|
|
1291
|
+
case "last-month":
|
|
1292
|
+
params.set("range", "last-month");
|
|
1293
|
+
break;
|
|
1294
|
+
case "last-3-months":
|
|
1295
|
+
params.set("range", "last-3-months");
|
|
1296
|
+
break;
|
|
1297
|
+
case "custom":
|
|
1298
|
+
default:
|
|
1299
|
+
if (rangeParam === "this-month" || rangeParam === "last-month" || rangeParam === "last-3-months") {
|
|
1300
|
+
const currentDate = presetToDateRange(rangeParam);
|
|
1301
|
+
params.set(
|
|
1302
|
+
"range",
|
|
1303
|
+
`${dateFns.format(currentDate.from || /* @__PURE__ */ new Date(), "yyyy-MM-dd")}-${dateFns.format(
|
|
1304
|
+
currentDate.to || /* @__PURE__ */ new Date(),
|
|
1305
|
+
"yyyy-MM-dd"
|
|
1306
|
+
)}`
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
setSearchParams(params);
|
|
1312
|
+
},
|
|
1313
|
+
[searchParams, rangeParam, setSearchParams]
|
|
1314
|
+
);
|
|
1315
|
+
const updateUrlParams = React__namespace.useCallback(
|
|
1316
|
+
(value) => {
|
|
1317
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1318
|
+
if ((value == null ? void 0 : value.from) && (value == null ? void 0 : value.to)) {
|
|
1319
|
+
params.set(
|
|
1320
|
+
"range",
|
|
1321
|
+
`${dateFns.format(value.from, "yyyy-MM-dd")}-${dateFns.format(
|
|
1322
|
+
value.to,
|
|
1323
|
+
"yyyy-MM-dd"
|
|
1324
|
+
)}`
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
setSearchParams(params);
|
|
1328
|
+
},
|
|
1329
|
+
[searchParams, setSearchParams]
|
|
1330
|
+
);
|
|
1294
1331
|
const handleDateRangeChange = React__namespace.useCallback(
|
|
1295
1332
|
(value) => {
|
|
1296
1333
|
const newDateRange = rangeValueToDateRange(value);
|
|
1297
|
-
|
|
1298
|
-
if (selectValue !== "custom") {
|
|
1299
|
-
setSelectValue("custom");
|
|
1300
|
-
}
|
|
1334
|
+
updateUrlParams(newDateRange);
|
|
1301
1335
|
},
|
|
1302
|
-
[]
|
|
1336
|
+
[updateUrlParams]
|
|
1303
1337
|
);
|
|
1304
1338
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
|
|
1305
1339
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-2 gap-y-4 items-center justify-between px-6 py-4", children: [
|
|
@@ -1310,7 +1344,9 @@ const AnalyticsPage = () => {
|
|
|
1310
1344
|
{
|
|
1311
1345
|
disabled: isLoadingOrders || isLoadingProducts,
|
|
1312
1346
|
defaultValue: "this-month",
|
|
1313
|
-
value:
|
|
1347
|
+
value: ["this-month", "last-month", "last-3-months"].includes(
|
|
1348
|
+
rangeParam
|
|
1349
|
+
) ? rangeParam : "custom",
|
|
1314
1350
|
onValueChange: updateDatePreset,
|
|
1315
1351
|
children: [
|
|
1316
1352
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, {}) }),
|
|
@@ -1406,193 +1442,204 @@ const AnalyticsPage = () => {
|
|
|
1406
1442
|
)
|
|
1407
1443
|
] })
|
|
1408
1444
|
] }),
|
|
1409
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1445
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1446
|
+
ui.Tabs,
|
|
1447
|
+
{
|
|
1448
|
+
value: searchParams.get("tab") || "orders",
|
|
1449
|
+
onValueChange: (value) => {
|
|
1450
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
1451
|
+
params.set("tab", value);
|
|
1452
|
+
setSearchParams(params);
|
|
1453
|
+
},
|
|
1454
|
+
children: [
|
|
1455
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.List, { children: [
|
|
1456
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1457
|
+
ui.Tabs.Trigger,
|
|
1458
|
+
{
|
|
1459
|
+
value: "orders",
|
|
1460
|
+
disabled: isLoadingOrders || isLoadingProducts,
|
|
1461
|
+
children: "Orders"
|
|
1462
|
+
}
|
|
1463
|
+
),
|
|
1464
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1465
|
+
ui.Tabs.Trigger,
|
|
1466
|
+
{
|
|
1467
|
+
value: "products",
|
|
1468
|
+
disabled: isLoadingOrders || isLoadingProducts,
|
|
1469
|
+
children: "Products"
|
|
1470
|
+
}
|
|
1471
|
+
)
|
|
1472
|
+
] }),
|
|
1473
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-8", children: [
|
|
1474
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.Content, { value: "orders", children: [
|
|
1475
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4 mb-4", children: [
|
|
1476
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 flex-1", children: [
|
|
1477
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
|
|
1478
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.ShoppingCart, { className: "absolute right-6 top-4 text-ui-fg-muted" }),
|
|
1479
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Total Orders" }),
|
|
1480
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1481
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: (orders == null ? void 0 : orders.total_orders) || 0 }),
|
|
1482
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
1483
|
+
((orders == null ? void 0 : orders.prev_orders_percent) || 0) > 0 && "+",
|
|
1484
|
+
(orders == null ? void 0 : orders.prev_orders_percent) || 0,
|
|
1485
|
+
"% from previous period"
|
|
1486
|
+
] })
|
|
1487
|
+
] })
|
|
1488
|
+
] }),
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1490
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Orders Over Time" }),
|
|
1491
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Total number of orders in the selected period" }),
|
|
1492
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(LineChartSkeleton, {}) : (orders == null ? void 0 : orders.order_count) && ((_d = orders == null ? void 0 : orders.order_count) == null ? void 0 : _d.length) > 0 && someOrderCountsGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1493
|
+
LineChart,
|
|
1494
|
+
{
|
|
1495
|
+
data: orders == null ? void 0 : orders.order_count,
|
|
1496
|
+
xAxisDataKey: "name",
|
|
1497
|
+
yAxisDataKey: "count"
|
|
1498
|
+
}
|
|
1499
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1500
|
+
ui.Text,
|
|
1501
|
+
{
|
|
1502
|
+
size: "small",
|
|
1503
|
+
className: "text-ui-fg-muted text-center",
|
|
1504
|
+
children: "No data available for the selected period."
|
|
1505
|
+
}
|
|
1506
|
+
)
|
|
1507
|
+
] })
|
|
1508
|
+
] }),
|
|
1509
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 flex-1", children: [
|
|
1510
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
|
|
1511
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChartNoAxesCombined, { className: "absolute right-6 text-ui-fg-muted top-4 size-[15px]" }),
|
|
1512
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Total Sales" }),
|
|
1513
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1514
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: new Intl.NumberFormat("en-US", {
|
|
1515
|
+
style: "currency",
|
|
1516
|
+
currency: (orders == null ? void 0 : orders.currency_code) || "EUR"
|
|
1517
|
+
}).format((orders == null ? void 0 : orders.total_sales) || 0) }),
|
|
1518
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
1519
|
+
((orders == null ? void 0 : orders.prev_sales_percent) || 0) > 0 && "+",
|
|
1520
|
+
(orders == null ? void 0 : orders.prev_sales_percent) || 0,
|
|
1521
|
+
"% from previous period"
|
|
1522
|
+
] })
|
|
1523
|
+
] })
|
|
1524
|
+
] }),
|
|
1525
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1526
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Sales Over Time" }),
|
|
1527
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: [
|
|
1528
|
+
"Total sales in the selected period (",
|
|
1529
|
+
orders == null ? void 0 : orders.currency_code,
|
|
1530
|
+
")"
|
|
1531
|
+
] }),
|
|
1532
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(LineChartSkeleton, {}) : (orders == null ? void 0 : orders.order_sales) && ((_e = orders == null ? void 0 : orders.order_sales) == null ? void 0 : _e.length) > 0 && someOrderSalesGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1533
|
+
LineChart,
|
|
1534
|
+
{
|
|
1535
|
+
data: orders.order_sales,
|
|
1536
|
+
xAxisDataKey: "name",
|
|
1537
|
+
yAxisDataKey: "sales",
|
|
1538
|
+
lineColor: "#82ca9d",
|
|
1539
|
+
yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
|
|
1540
|
+
currency: orders.currency_code,
|
|
1541
|
+
maximumFractionDigits: 0
|
|
1542
|
+
}).format(value)
|
|
1543
|
+
}
|
|
1544
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1545
|
+
ui.Text,
|
|
1546
|
+
{
|
|
1547
|
+
size: "small",
|
|
1548
|
+
className: "text-ui-fg-muted text-center",
|
|
1549
|
+
children: "No data available for the selected period."
|
|
1550
|
+
}
|
|
1551
|
+
)
|
|
1441
1552
|
] })
|
|
1442
1553
|
] })
|
|
1443
1554
|
] }),
|
|
1444
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1445
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1555
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4", children: [
|
|
1556
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1557
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top Regions by Sales" }),
|
|
1558
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Sales breakdown by region in the selected period" }),
|
|
1559
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (orders == null ? void 0 : orders.regions) && ((_f = orders == null ? void 0 : orders.regions) == null ? void 0 : _f.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1560
|
+
BarChart,
|
|
1561
|
+
{
|
|
1562
|
+
data: orders.regions,
|
|
1563
|
+
xAxisDataKey: "name",
|
|
1564
|
+
yAxisDataKey: "sales",
|
|
1565
|
+
lineColor: "#82ca9d",
|
|
1566
|
+
useStableColors: true,
|
|
1567
|
+
colorKeyField: "name",
|
|
1568
|
+
yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
|
|
1569
|
+
currency: orders.currency_code,
|
|
1570
|
+
maximumFractionDigits: 0
|
|
1571
|
+
}).format(value)
|
|
1572
|
+
}
|
|
1573
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1574
|
+
ui.Text,
|
|
1575
|
+
{
|
|
1576
|
+
size: "small",
|
|
1577
|
+
className: "text-ui-fg-muted text-center",
|
|
1578
|
+
children: "No data available for the selected period."
|
|
1579
|
+
}
|
|
1580
|
+
)
|
|
1581
|
+
] }) }),
|
|
1582
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1583
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Order Status Breakdown" }),
|
|
1584
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Distribution of orders by status in the selected period" }),
|
|
1585
|
+
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(PieChartSkeleton, {}) : (orders == null ? void 0 : orders.statuses) && ((_g = orders == null ? void 0 : orders.statuses) == null ? void 0 : _g.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: orders == null ? void 0 : orders.statuses, dataKey: "count" }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1586
|
+
ui.Text,
|
|
1587
|
+
{
|
|
1588
|
+
size: "small",
|
|
1589
|
+
className: "text-ui-fg-muted text-center",
|
|
1590
|
+
children: "No data available for the selected period."
|
|
1591
|
+
}
|
|
1592
|
+
)
|
|
1593
|
+
] }) })
|
|
1462
1594
|
] })
|
|
1463
1595
|
] }),
|
|
1464
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1465
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "
|
|
1466
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1467
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
style: "currency",
|
|
1471
|
-
currency: (orders == null ? void 0 : orders.currency_code) || "EUR"
|
|
1472
|
-
}).format((orders == null ? void 0 : orders.total_sales) || 0) }),
|
|
1473
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
|
|
1474
|
-
((orders == null ? void 0 : orders.prev_sales_percent) || 0) > 0 && "+",
|
|
1475
|
-
(orders == null ? void 0 : orders.prev_sales_percent) || 0,
|
|
1476
|
-
"% from previous period"
|
|
1477
|
-
] })
|
|
1478
|
-
] })
|
|
1479
|
-
] }),
|
|
1480
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1481
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Sales Over Time" }),
|
|
1482
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: [
|
|
1483
|
-
"Total sales in the selected period (",
|
|
1484
|
-
orders == null ? void 0 : orders.currency_code,
|
|
1485
|
-
")"
|
|
1486
|
-
] }),
|
|
1487
|
-
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(LineChartSkeleton, {}) : (orders == null ? void 0 : orders.order_sales) && ((_e = orders == null ? void 0 : orders.order_sales) == null ? void 0 : _e.length) > 0 && someOrderSalesGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1488
|
-
LineChart,
|
|
1596
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.Content, { value: "products", children: [
|
|
1597
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "mb-4 min-h-[9.375rem]", children: [
|
|
1598
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top-Selling Products" }),
|
|
1599
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products by quantity sold in selected period" }),
|
|
1600
|
+
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (products == null ? void 0 : products.variantQuantitySold) && someTopSellingProductsGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1601
|
+
BarChart,
|
|
1489
1602
|
{
|
|
1490
|
-
data:
|
|
1491
|
-
xAxisDataKey: "
|
|
1492
|
-
yAxisDataKey: "
|
|
1603
|
+
data: products.variantQuantitySold,
|
|
1604
|
+
xAxisDataKey: "title",
|
|
1605
|
+
yAxisDataKey: "quantity",
|
|
1493
1606
|
lineColor: "#82ca9d",
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
maximumFractionDigits: 0
|
|
1497
|
-
}).format(value)
|
|
1607
|
+
useStableColors: true,
|
|
1608
|
+
colorKeyField: "title"
|
|
1498
1609
|
}
|
|
1499
|
-
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1610
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted text-center", children: "No data available for the selected period." })
|
|
1611
|
+
] }),
|
|
1612
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 max-xl:flex-col", children: [
|
|
1613
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1614
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Out-of-Stock Variants" }),
|
|
1615
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with zero inventory" }),
|
|
1616
|
+
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1617
|
+
ProductsTable,
|
|
1618
|
+
{
|
|
1619
|
+
products: ((_h = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _h.filter(
|
|
1620
|
+
(product) => product.inventoryQuantity === 0
|
|
1621
|
+
)) || []
|
|
1622
|
+
}
|
|
1623
|
+
)
|
|
1624
|
+
] }),
|
|
1625
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1626
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Low Stock Variants" }),
|
|
1627
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with inventory below threshold" }),
|
|
1628
|
+
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1629
|
+
ProductsTable,
|
|
1630
|
+
{
|
|
1631
|
+
products: ((_i = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _i.filter(
|
|
1632
|
+
(product) => product.inventoryQuantity > 0
|
|
1633
|
+
)) || []
|
|
1634
|
+
}
|
|
1635
|
+
)
|
|
1636
|
+
] })
|
|
1507
1637
|
] })
|
|
1508
1638
|
] })
|
|
1509
|
-
] }),
|
|
1510
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4", children: [
|
|
1511
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1512
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top Regions by Sales" }),
|
|
1513
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Sales breakdown by region in the selected period" }),
|
|
1514
|
-
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (orders == null ? void 0 : orders.regions) && ((_f = orders == null ? void 0 : orders.regions) == null ? void 0 : _f.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1515
|
-
BarChart,
|
|
1516
|
-
{
|
|
1517
|
-
data: orders.regions,
|
|
1518
|
-
xAxisDataKey: "name",
|
|
1519
|
-
yAxisDataKey: "sales",
|
|
1520
|
-
lineColor: "#82ca9d",
|
|
1521
|
-
useStableColors: true,
|
|
1522
|
-
colorKeyField: "name",
|
|
1523
|
-
yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
|
|
1524
|
-
currency: orders.currency_code,
|
|
1525
|
-
maximumFractionDigits: 0
|
|
1526
|
-
}).format(value)
|
|
1527
|
-
}
|
|
1528
|
-
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1529
|
-
ui.Text,
|
|
1530
|
-
{
|
|
1531
|
-
size: "small",
|
|
1532
|
-
className: "text-ui-fg-muted text-center",
|
|
1533
|
-
children: "No data available for the selected period."
|
|
1534
|
-
}
|
|
1535
|
-
)
|
|
1536
|
-
] }) }),
|
|
1537
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "min-h-[9.375rem]", children: [
|
|
1538
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Order Status Breakdown" }),
|
|
1539
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Distribution of orders by status in the selected period" }),
|
|
1540
|
-
isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(PieChartSkeleton, {}) : (orders == null ? void 0 : orders.statuses) && ((_g = orders == null ? void 0 : orders.statuses) == null ? void 0 : _g.length) > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: orders == null ? void 0 : orders.statuses, dataKey: "count" }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1541
|
-
ui.Text,
|
|
1542
|
-
{
|
|
1543
|
-
size: "small",
|
|
1544
|
-
className: "text-ui-fg-muted text-center",
|
|
1545
|
-
children: "No data available for the selected period."
|
|
1546
|
-
}
|
|
1547
|
-
)
|
|
1548
|
-
] }) })
|
|
1549
1639
|
] })
|
|
1550
|
-
]
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Top-Selling Products" }),
|
|
1554
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products by quantity sold in selected period" }),
|
|
1555
|
-
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(BarChartSkeleton, {}) : (products == null ? void 0 : products.variantQuantitySold) && someTopSellingProductsGreaterThanZero ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", style: { aspectRatio: "16/9" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1556
|
-
BarChart,
|
|
1557
|
-
{
|
|
1558
|
-
data: products.variantQuantitySold,
|
|
1559
|
-
xAxisDataKey: "title",
|
|
1560
|
-
yAxisDataKey: "quantity",
|
|
1561
|
-
lineColor: "#82ca9d",
|
|
1562
|
-
useStableColors: true,
|
|
1563
|
-
colorKeyField: "title"
|
|
1564
|
-
}
|
|
1565
|
-
) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted text-center", children: "No data available for the selected period." })
|
|
1566
|
-
] }),
|
|
1567
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 max-xl:flex-col", children: [
|
|
1568
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1569
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Out-of-Stock Variants" }),
|
|
1570
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with zero inventory" }),
|
|
1571
|
-
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1572
|
-
ProductsTable,
|
|
1573
|
-
{
|
|
1574
|
-
products: ((_h = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _h.filter(
|
|
1575
|
-
(product) => product.inventoryQuantity === 0
|
|
1576
|
-
)) || []
|
|
1577
|
-
}
|
|
1578
|
-
)
|
|
1579
|
-
] }),
|
|
1580
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
|
|
1581
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Low Stock Variants" }),
|
|
1582
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Products with inventory below threshold" }),
|
|
1583
|
-
isLoadingProducts ? /* @__PURE__ */ jsxRuntime.jsx(ProductsTableSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1584
|
-
ProductsTable,
|
|
1585
|
-
{
|
|
1586
|
-
products: ((_i = products == null ? void 0 : products.lowStockVariants) == null ? void 0 : _i.filter(
|
|
1587
|
-
(product) => product.inventoryQuantity > 0
|
|
1588
|
-
)) || []
|
|
1589
|
-
}
|
|
1590
|
-
)
|
|
1591
|
-
] })
|
|
1592
|
-
] })
|
|
1593
|
-
] })
|
|
1594
|
-
] })
|
|
1595
|
-
] }) })
|
|
1640
|
+
]
|
|
1641
|
+
}
|
|
1642
|
+
) })
|
|
1596
1643
|
] });
|
|
1597
1644
|
};
|
|
1598
1645
|
const config = adminSdk.defineRouteConfig({
|