@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.
@@ -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.jsxs("div", { className: "space-y-2", children: [
679
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-muted mb-2", children: "Single day selected - showing as bar chart for better visibility" }) }),
680
- /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { aspect: 16 / 9, children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data, margin: { left: 20 }, children: [
681
- /* @__PURE__ */ jsxRuntime.jsx(
682
- recharts.CartesianGrid,
683
- {
684
- strokeDasharray: "3 3",
685
- stroke: isDark ? "#374151" : "#E5E7EB"
686
- }
687
- ),
688
- /* @__PURE__ */ jsxRuntime.jsx(
689
- recharts.XAxis,
690
- {
691
- dataKey: xAxisDataKey,
692
- tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
693
- axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
694
- tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
695
- tickMargin: 10
696
- }
697
- ),
698
- /* @__PURE__ */ jsxRuntime.jsx(
699
- recharts.YAxis,
700
- {
701
- tickFormatter: yAxisTickFormatter,
702
- allowDecimals: false,
703
- tick: { fill: isDark ? "#D1D5DB" : "#6B7280" },
704
- axisLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" },
705
- tickLine: { stroke: isDark ? "#4B5563" : "#D1D5DB" }
706
- }
707
- ),
708
- /* @__PURE__ */ jsxRuntime.jsx(
709
- recharts.Tooltip,
710
- {
711
- cursor: {
712
- fill: isDark ? "rgba(55, 65, 81, 0.2)" : "rgba(243, 244, 246, 0.5)"
713
- },
714
- formatter: (value) => yAxisTickFormatter ? yAxisTickFormatter(value) : value,
715
- contentStyle: {
716
- backgroundColor: isDark ? "#1F2937" : "#FFFFFF",
717
- border: `1px solid ${isDark ? "#374151" : "#E5E7EB"}`,
718
- borderRadius: "0.5rem",
719
- color: isDark ? "#F9FAFB" : "#111827",
720
- boxShadow: isDark ? "0 4px 6px -1px rgba(0, 0, 0, 0.3)" : "0 4px 6px -1px rgba(0, 0, 0, 0.1)"
721
- },
722
- labelStyle: {
723
- color: isDark ? "#F9FAFB" : "#111827",
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 = window.location.origin;
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 = window.location.origin;
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 [date, setDate] = React__namespace.useState({
1248
- from: dateFns.startOfMonth(/* @__PURE__ */ new Date()),
1249
- to: dateFns.endOfMonth(/* @__PURE__ */ new Date())
1250
- });
1251
- const [selectValue, setSelectValue] = React__namespace.useState("this-month");
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
- selectValue,
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((preset) => {
1265
- const today = /* @__PURE__ */ new Date();
1266
- switch (preset) {
1267
- case "this-month":
1268
- setDate({
1269
- from: dateFns.startOfMonth(today),
1270
- to: today
1271
- });
1272
- setSelectValue("this-month");
1273
- break;
1274
- case "last-month":
1275
- setDate({
1276
- from: dateFns.startOfMonth(dateFns.subMonths(today, 1)),
1277
- to: dateFns.endOfMonth(dateFns.subMonths(today, 1))
1278
- });
1279
- setSelectValue("last-month");
1280
- break;
1281
- case "last-3-months":
1282
- setDate({
1283
- from: dateFns.startOfMonth(dateFns.subMonths(today, 3)),
1284
- to: dateFns.endOfMonth(dateFns.subMonths(today, 1))
1285
- });
1286
- setSelectValue("last-3-months");
1287
- break;
1288
- case "custom":
1289
- default:
1290
- setSelectValue("custom");
1291
- break;
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
- setDate(newDateRange);
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: selectValue,
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(ui.Tabs, { defaultValue: "orders", children: [
1410
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.List, { children: [
1411
- /* @__PURE__ */ jsxRuntime.jsx(
1412
- ui.Tabs.Trigger,
1413
- {
1414
- value: "orders",
1415
- disabled: isLoadingOrders || isLoadingProducts,
1416
- children: "Orders"
1417
- }
1418
- ),
1419
- /* @__PURE__ */ jsxRuntime.jsx(
1420
- ui.Tabs.Trigger,
1421
- {
1422
- value: "products",
1423
- disabled: isLoadingOrders || isLoadingProducts,
1424
- children: "Products"
1425
- }
1426
- )
1427
- ] }),
1428
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-8", children: [
1429
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.Content, { value: "orders", children: [
1430
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-md:flex-col gap-4 mb-4", children: [
1431
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 flex-1", children: [
1432
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
1433
- /* @__PURE__ */ jsxRuntime.jsx(icons.ShoppingCart, { className: "absolute right-6 top-4 text-ui-fg-muted" }),
1434
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Total Orders" }),
1435
- isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1436
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: (orders == null ? void 0 : orders.total_orders) || 0 }),
1437
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
1438
- ((orders == null ? void 0 : orders.prev_orders_percent) || 0) > 0 && "+",
1439
- (orders == null ? void 0 : orders.prev_orders_percent) || 0,
1440
- "% from previous period"
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(ui.Container, { className: "min-h-[9.375rem]", children: [
1445
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: "Orders Over Time" }),
1446
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "mb-8 text-ui-fg-muted", children: "Total number of orders in the selected period" }),
1447
- 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(
1448
- LineChart,
1449
- {
1450
- data: orders == null ? void 0 : orders.order_count,
1451
- xAxisDataKey: "name",
1452
- yAxisDataKey: "count"
1453
- }
1454
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
1455
- ui.Text,
1456
- {
1457
- size: "small",
1458
- className: "text-ui-fg-muted text-center",
1459
- children: "No data available for the selected period."
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("div", { className: "space-y-4 flex-1", children: [
1465
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "relative", children: [
1466
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChartNoAxesCombined, { className: "absolute right-6 text-ui-fg-muted top-4 size-[15px]" }),
1467
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: "Total Sales" }),
1468
- isLoadingOrders ? /* @__PURE__ */ jsxRuntime.jsx(SmallCardSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1469
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xlarge", weight: "plus", children: new Intl.NumberFormat("en-US", {
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: orders.order_sales,
1491
- xAxisDataKey: "name",
1492
- yAxisDataKey: "sales",
1603
+ data: products.variantQuantitySold,
1604
+ xAxisDataKey: "title",
1605
+ yAxisDataKey: "quantity",
1493
1606
  lineColor: "#82ca9d",
1494
- yAxisTickFormatter: (value) => new Intl.NumberFormat("en-US", {
1495
- currency: orders.currency_code,
1496
- maximumFractionDigits: 0
1497
- }).format(value)
1607
+ useStableColors: true,
1608
+ colorKeyField: "title"
1498
1609
  }
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
- )
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
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.Content, { value: "products", children: [
1552
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "mb-4 min-h-[9.375rem]", children: [
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({